Skip to content

Commit

Permalink
Upgrade GraphiQL to 3.0.5 version (#1188, #1069)
Browse files Browse the repository at this point in the history
- track GraphiQL new version via @dependabot
- automate GraphiQL integration glue adapting for new versions
- rework `example/warp_subscriptions`  to support subscriptions in new GraphiQL
  • Loading branch information
tyranron authored Sep 13, 2023
1 parent f172be5 commit f9d9027
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 140 deletions.
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ updates:
directory: /
schedule:
interval: daily

- package-ecosystem: npm
directory: /juniper/
schedule:
interval: daily
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,29 @@ book.serve:



######################
# Forwarded commands #
######################

# Download and prepare actual version of GraphiQL static files, used for
# integrating it.
#
# Usage:
# make graphiql

graphiql:
@cd juniper/ && \
make graphiql




##################
# .PHONY section #
##################

.PHONY: book fmt lint release test \
book.build book.serve \
cargo.fmt cargo.lint cargo.release cargo.test \
graphiql \
test.book test.cargo
1 change: 1 addition & 0 deletions examples/warp_subscriptions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ env_logger = "0.10"
futures = "0.3"
juniper = { path = "../../juniper" }
juniper_graphql_ws = { path = "../../juniper_graphql_ws" }
juniper_graphql_transport_ws = { path = "../../juniper_graphql_transport_ws" }
juniper_warp = { path = "../../juniper_warp", features = ["subscriptions"] }
log = "0.4.8"
serde = { version = "1.0", features = ["derive"] }
Expand Down
82 changes: 54 additions & 28 deletions examples/warp_subscriptions/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ use juniper::{
graphql_object, graphql_subscription, graphql_value, EmptyMutation, FieldError, GraphQLEnum,
RootNode,
};
use juniper_graphql_ws::ConnectionConfig;
use juniper_warp::{playground_filter, subscriptions::serve_graphql_ws};
use juniper_graphql_transport_ws::ConnectionConfig;
use juniper_graphql_ws::ConnectionConfig as LegacyConnectionConfig;
use juniper_warp::{
graphiql_filter, playground_filter,
subscriptions::{serve_graphql_transport_ws, serve_graphql_ws},
};
use warp::{http::Response, Filter};

#[derive(Clone)]
Expand Down Expand Up @@ -108,13 +112,13 @@ struct Subscription;
#[graphql_subscription(context = Context)]
impl Subscription {
async fn users() -> UsersStream {
let mut counter = 0;
let mut interval = tokio::time::interval(Duration::from_secs(5));
let stream = async_stream::stream! {
counter += 1;
let mut counter = 0;
loop {
counter += 1;
interval.tick().await;
if counter == 2 {
if counter == 5 {
yield Err(FieldError::new(
"some field error from handler",
graphql_value!("some additional string"),
Expand Down Expand Up @@ -156,36 +160,58 @@ async fn main() {
let qm_state = warp::any().map(|| Context);
let qm_graphql_filter = juniper_warp::make_graphql_filter(qm_schema, qm_state.boxed());

let root_node = Arc::new(schema());
let ws_schema = Arc::new(schema());
let transport_ws_schema = ws_schema.clone();

log::info!("Listening on 127.0.0.1:8080");

let routes = (warp::path("subscriptions")
let routes = warp::path("subscriptions")
.and(warp::ws())
.map(move |ws: warp::ws::Ws| {
let root_node = root_node.clone();
let transport_ws_schema = transport_ws_schema.clone();
ws.on_upgrade(move |websocket| async move {
serve_graphql_ws(websocket, root_node, ConnectionConfig::new(Context))
.map(|r| {
if let Err(e) = r {
println!("Websocket error: {e}");
}
})
.await
serve_graphql_transport_ws(
websocket,
transport_ws_schema,
ConnectionConfig::new(Context),
)
.map(|r| {
if let Err(e) = r {
println!("Websocket error: {e}");
}
})
.await
})
})
.or(warp::path("legacy-subscriptions")
.and(warp::ws())
.map(move |ws: warp::ws::Ws| {
let ws_schema = ws_schema.clone();
ws.on_upgrade(move |websocket| async move {
serve_graphql_ws(websocket, ws_schema, LegacyConnectionConfig::new(Context))
.map(|r| {
if let Err(e) = r {
println!("Websocket error: {e}");
}
})
.await
})
})
}))
.map(|reply| {
// TODO#584: remove this workaround
warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
})
.or(warp::post()
.and(warp::path("graphql"))
.and(qm_graphql_filter))
.or(warp::get()
.and(warp::path("playground"))
.and(playground_filter("/graphql", Some("/subscriptions"))))
.or(homepage)
.with(log);
.map(|reply| {
// TODO#584: remove this workaround
warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
}))
.or(warp::post()
.and(warp::path("graphql"))
.and(qm_graphql_filter))
.or(warp::get()
.and(warp::path("playground"))
.and(playground_filter("/graphql", Some("/legacy-subscriptions"))))
.or(warp::get()
.and(warp::path("graphiql"))
.and(graphiql_filter("/graphql", Some("/subscriptions"))))
.or(homepage)
.with(log);

warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
}
3 changes: 3 additions & 0 deletions juniper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules/
/package-lock.json
/yarn.lock
4 changes: 4 additions & 0 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- Disabled `chrono` [Cargo feature] by default.
- Removed `scalar-naivetime` [Cargo feature].
- Removed lifetime parameter from `ParseError`, `GraphlQLError`, `GraphQLBatchRequest` and `GraphQLRequest`. ([#1081], [#528])
- Upgraded [GraphiQL] to 3.0.5 version (requires new [`graphql-ws` GraphQL over WebSocket Protocol] integration on server, see `examples/warp_subscriptions`). ([#1188])

### Added

Expand Down Expand Up @@ -121,6 +122,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
[#1145]: /../../pull/1145
[#1147]: /../../pull/1147
[#1176]: /../../pull/1176
[#1188]: /../../pull/1188
[ba1ed85b]: /../../commit/ba1ed85b3c3dd77fbae7baf6bc4e693321a94083
[CVE-2022-31173]: /../../security/advisories/GHSA-4rx6-g5vg-5f3j

Expand All @@ -140,6 +142,8 @@ See [old CHANGELOG](/../../blob/juniper-v0.15.9/juniper/CHANGELOG.md).
[`chrono-tz` crate]: https://docs.rs/chrono-tz
[`time` crate]: https://docs.rs/time
[Cargo feature]: https://doc.rust-lang.org/cargo/reference/features.html
[`graphql-ws` GraphQL over WebSocket Protocol]: https://github.com/graphql/graphiql
[GraphiQL]: https://github.com/enisdenjo/graphql-ws/master/PROTOCOL.md
[graphql-scalars.dev]: https://graphql-scalars.dev
[October 2021]: https://spec.graphql.org/October2021
[object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
Expand Down
2 changes: 1 addition & 1 deletion juniper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repository = "https://github.com/graphql-rust/juniper"
readme = "README.md"
categories = ["asynchronous", "web-programming", "web-programming::http-server"]
keywords = ["apollo", "graphql", "server", "web"]
exclude = ["/release.toml"]
include = ["/src/", "/CHANGELOG.md", "/LICENSE", "/README.md"]

[package.metadata.docs.rs]
all-features = true
Expand Down
56 changes: 56 additions & 0 deletions juniper/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
###############################
# Common defaults/definitions #
###############################

# Checks two given strings for equality.
eq = $(if $(or $(1),$(2)),$(and $(findstring $(1),$(2)),\
$(findstring $(2),$(1))),1)

# Multiplatform prefix of `sed -i` commands.
sed-i = sed -i$(if $(call eq,$(shell uname -s),Darwin), '',)




######################
# Project parameters #
######################

GRAPHIQL_VER ?= $(strip \
$(shell grep -m1 '"graphiql": "' package.json | cut -d '"' -f4))




############
# Commands #
############

# Download and prepare actual version of GraphiQL static files, used for
# integrating it.
#
# Usage:
# make graphiql

graphiql:
curl -fL -o src/http/graphiql.html \
https://raw.githubusercontent.com/graphql/graphiql/graphiql%40$(GRAPHIQL_VER)/examples/graphiql-cdn/index.html
$(sed-i) 's|https://unpkg.com/graphiql/|https://unpkg.com/graphiql@$(GRAPHIQL_VER)/|g' \
src/http/graphiql.html
$(sed-i) "s|'https://swapi-graphql.netlify.app/.netlify/functions/index'|GRAPHQL_URL|g" \
src/http/graphiql.html
$(sed-i) "s|url: GRAPHQL_URL,|url: GRAPHQL_URL,\n subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)|" \
src/http/graphiql.html
$(sed-i) 's|<script>|<script>\n<!-- inject -->|' \
src/http/graphiql.html
$(sed-i) '/X-Example-Header/d' \
src/http/graphiql.html




##################
# .PHONY section #
##################

.PHONY: graphiql
9 changes: 9 additions & 0 deletions juniper/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"private": true,
"scripts": {
"postinstall": "make graphiql"
},
"dependencies": {
"graphiql": "3.0.5"
}
}
75 changes: 75 additions & 0 deletions juniper/src/http/graphiql.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!--
* Copyright (c) 2021 GraphQL Contributors
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
-->
<!doctype html>
<html lang="en">
<head>
<title>GraphiQL</title>
<style>
body {
height: 100%;
margin: 0;
width: 100%;
overflow: hidden;
}

#graphiql {
height: 100vh;
}
</style>

<!--
This GraphiQL example depends on Promise and fetch, which are available in
modern browsers, but can be "polyfilled" for older browsers.
GraphiQL itself depends on React DOM.
If you do not want to rely on a CDN, you can host these files locally or
include them directly in your favored resource bundler.
-->
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script
src="https://unpkg.com/graphiql@3.0.5/graphiql.min.js"
type="application/javascript"
></script>
<script
src="https://unpkg.com/@graphiql/plugin-explorer/dist/index.umd.js"
crossorigin
></script>
<!--
These two files can be found in the npm module, however you may wish to
copy them directly into your environment, or perhaps include them in your
favored resource bundler.
-->
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.0.5/graphiql.min.css" />
</head>

<body>
<div id="graphiql">Loading...</div>
<script>
<!-- inject -->
const root = ReactDOM.createRoot(document.getElementById('graphiql'));
const fetcher = GraphiQL.createFetcher({
url: GRAPHQL_URL,
subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)
});
const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin();
root.render(
React.createElement(GraphiQL, {
fetcher,
defaultEditorToolsVisibility: true,
plugins: [explorerPlugin],
}),
);
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions juniper/src/http/graphiql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function normalizeSubscriptionEndpoint(endpoint, subscriptionEndpoint) {
if (subscriptionEndpoint) {
if (subscriptionEndpoint.startsWith('/')) {
const secure =
endpoint.includes('https') || location.href.includes('https')
? 's'
: ''
return `ws${secure}://${location.host}${subscriptionEndpoint}`
} else {
return subscriptionEndpoint.replace(/^http/, 'ws')
}
}
return null
}
Loading

0 comments on commit f9d9027

Please sign in to comment.