Skip to content

Commit f9d9027

Browse files
authored
Upgrade GraphiQL to 3.0.5 version (#1188, #1069)
- track GraphiQL new version via @dependabot - automate GraphiQL integration glue adapting for new versions - rework `example/warp_subscriptions` to support subscriptions in new GraphiQL
1 parent f172be5 commit f9d9027

File tree

14 files changed

+259
-140
lines changed

14 files changed

+259
-140
lines changed

.github/dependabot.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ updates:
99
directory: /
1010
schedule:
1111
interval: daily
12+
13+
- package-ecosystem: npm
14+
directory: /juniper/
15+
schedule:
16+
interval: daily

Makefile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,29 @@ book.serve:
148148

149149

150150

151+
######################
152+
# Forwarded commands #
153+
######################
154+
155+
# Download and prepare actual version of GraphiQL static files, used for
156+
# integrating it.
157+
#
158+
# Usage:
159+
# make graphiql
160+
161+
graphiql:
162+
@cd juniper/ && \
163+
make graphiql
164+
165+
166+
167+
151168
##################
152169
# .PHONY section #
153170
##################
154171

155172
.PHONY: book fmt lint release test \
156173
book.build book.serve \
157174
cargo.fmt cargo.lint cargo.release cargo.test \
175+
graphiql \
158176
test.book test.cargo

examples/warp_subscriptions/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ env_logger = "0.10"
1111
futures = "0.3"
1212
juniper = { path = "../../juniper" }
1313
juniper_graphql_ws = { path = "../../juniper_graphql_ws" }
14+
juniper_graphql_transport_ws = { path = "../../juniper_graphql_transport_ws" }
1415
juniper_warp = { path = "../../juniper_warp", features = ["subscriptions"] }
1516
log = "0.4.8"
1617
serde = { version = "1.0", features = ["derive"] }

examples/warp_subscriptions/src/main.rs

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ use juniper::{
77
graphql_object, graphql_subscription, graphql_value, EmptyMutation, FieldError, GraphQLEnum,
88
RootNode,
99
};
10-
use juniper_graphql_ws::ConnectionConfig;
11-
use juniper_warp::{playground_filter, subscriptions::serve_graphql_ws};
10+
use juniper_graphql_transport_ws::ConnectionConfig;
11+
use juniper_graphql_ws::ConnectionConfig as LegacyConnectionConfig;
12+
use juniper_warp::{
13+
graphiql_filter, playground_filter,
14+
subscriptions::{serve_graphql_transport_ws, serve_graphql_ws},
15+
};
1216
use warp::{http::Response, Filter};
1317

1418
#[derive(Clone)]
@@ -108,13 +112,13 @@ struct Subscription;
108112
#[graphql_subscription(context = Context)]
109113
impl Subscription {
110114
async fn users() -> UsersStream {
111-
let mut counter = 0;
112115
let mut interval = tokio::time::interval(Duration::from_secs(5));
113116
let stream = async_stream::stream! {
114-
counter += 1;
117+
let mut counter = 0;
115118
loop {
119+
counter += 1;
116120
interval.tick().await;
117-
if counter == 2 {
121+
if counter == 5 {
118122
yield Err(FieldError::new(
119123
"some field error from handler",
120124
graphql_value!("some additional string"),
@@ -156,36 +160,58 @@ async fn main() {
156160
let qm_state = warp::any().map(|| Context);
157161
let qm_graphql_filter = juniper_warp::make_graphql_filter(qm_schema, qm_state.boxed());
158162

159-
let root_node = Arc::new(schema());
163+
let ws_schema = Arc::new(schema());
164+
let transport_ws_schema = ws_schema.clone();
160165

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

163-
let routes = (warp::path("subscriptions")
168+
let routes = warp::path("subscriptions")
164169
.and(warp::ws())
165170
.map(move |ws: warp::ws::Ws| {
166-
let root_node = root_node.clone();
171+
let transport_ws_schema = transport_ws_schema.clone();
167172
ws.on_upgrade(move |websocket| async move {
168-
serve_graphql_ws(websocket, root_node, ConnectionConfig::new(Context))
169-
.map(|r| {
170-
if let Err(e) = r {
171-
println!("Websocket error: {e}");
172-
}
173-
})
174-
.await
173+
serve_graphql_transport_ws(
174+
websocket,
175+
transport_ws_schema,
176+
ConnectionConfig::new(Context),
177+
)
178+
.map(|r| {
179+
if let Err(e) = r {
180+
println!("Websocket error: {e}");
181+
}
182+
})
183+
.await
184+
})
185+
})
186+
.or(warp::path("legacy-subscriptions")
187+
.and(warp::ws())
188+
.map(move |ws: warp::ws::Ws| {
189+
let ws_schema = ws_schema.clone();
190+
ws.on_upgrade(move |websocket| async move {
191+
serve_graphql_ws(websocket, ws_schema, LegacyConnectionConfig::new(Context))
192+
.map(|r| {
193+
if let Err(e) = r {
194+
println!("Websocket error: {e}");
195+
}
196+
})
197+
.await
198+
})
175199
})
176-
}))
177-
.map(|reply| {
178-
// TODO#584: remove this workaround
179-
warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
180-
})
181-
.or(warp::post()
182-
.and(warp::path("graphql"))
183-
.and(qm_graphql_filter))
184-
.or(warp::get()
185-
.and(warp::path("playground"))
186-
.and(playground_filter("/graphql", Some("/subscriptions"))))
187-
.or(homepage)
188-
.with(log);
200+
.map(|reply| {
201+
// TODO#584: remove this workaround
202+
warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
203+
}))
204+
.or(warp::post()
205+
.and(warp::path("graphql"))
206+
.and(qm_graphql_filter))
207+
.or(warp::get()
208+
.and(warp::path("playground"))
209+
.and(playground_filter("/graphql", Some("/legacy-subscriptions"))))
210+
.or(warp::get()
211+
.and(warp::path("graphiql"))
212+
.and(graphiql_filter("/graphql", Some("/subscriptions"))))
213+
.or(homepage)
214+
.with(log);
189215

190216
warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
191217
}

juniper/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/node_modules/
2+
/package-lock.json
3+
/yarn.lock

juniper/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
5151
- Disabled `chrono` [Cargo feature] by default.
5252
- Removed `scalar-naivetime` [Cargo feature].
5353
- Removed lifetime parameter from `ParseError`, `GraphlQLError`, `GraphQLBatchRequest` and `GraphQLRequest`. ([#1081], [#528])
54+
- Upgraded [GraphiQL] to 3.0.5 version (requires new [`graphql-ws` GraphQL over WebSocket Protocol] integration on server, see `examples/warp_subscriptions`). ([#1188])
5455

5556
### Added
5657

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

@@ -140,6 +142,8 @@ See [old CHANGELOG](/../../blob/juniper-v0.15.9/juniper/CHANGELOG.md).
140142
[`chrono-tz` crate]: https://docs.rs/chrono-tz
141143
[`time` crate]: https://docs.rs/time
142144
[Cargo feature]: https://doc.rust-lang.org/cargo/reference/features.html
145+
[`graphql-ws` GraphQL over WebSocket Protocol]: https://github.com/graphql/graphiql
146+
[GraphiQL]: https://github.com/enisdenjo/graphql-ws/master/PROTOCOL.md
143147
[graphql-scalars.dev]: https://graphql-scalars.dev
144148
[October 2021]: https://spec.graphql.org/October2021
145149
[object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety

juniper/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ repository = "https://github.com/graphql-rust/juniper"
1818
readme = "README.md"
1919
categories = ["asynchronous", "web-programming", "web-programming::http-server"]
2020
keywords = ["apollo", "graphql", "server", "web"]
21-
exclude = ["/release.toml"]
21+
include = ["/src/", "/CHANGELOG.md", "/LICENSE", "/README.md"]
2222

2323
[package.metadata.docs.rs]
2424
all-features = true

juniper/Makefile

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
###############################
2+
# Common defaults/definitions #
3+
###############################
4+
5+
# Checks two given strings for equality.
6+
eq = $(if $(or $(1),$(2)),$(and $(findstring $(1),$(2)),\
7+
$(findstring $(2),$(1))),1)
8+
9+
# Multiplatform prefix of `sed -i` commands.
10+
sed-i = sed -i$(if $(call eq,$(shell uname -s),Darwin), '',)
11+
12+
13+
14+
15+
######################
16+
# Project parameters #
17+
######################
18+
19+
GRAPHIQL_VER ?= $(strip \
20+
$(shell grep -m1 '"graphiql": "' package.json | cut -d '"' -f4))
21+
22+
23+
24+
25+
############
26+
# Commands #
27+
############
28+
29+
# Download and prepare actual version of GraphiQL static files, used for
30+
# integrating it.
31+
#
32+
# Usage:
33+
# make graphiql
34+
35+
graphiql:
36+
curl -fL -o src/http/graphiql.html \
37+
https://raw.githubusercontent.com/graphql/graphiql/graphiql%40$(GRAPHIQL_VER)/examples/graphiql-cdn/index.html
38+
$(sed-i) 's|https://unpkg.com/graphiql/|https://unpkg.com/graphiql@$(GRAPHIQL_VER)/|g' \
39+
src/http/graphiql.html
40+
$(sed-i) "s|'https://swapi-graphql.netlify.app/.netlify/functions/index'|GRAPHQL_URL|g" \
41+
src/http/graphiql.html
42+
$(sed-i) "s|url: GRAPHQL_URL,|url: GRAPHQL_URL,\n subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)|" \
43+
src/http/graphiql.html
44+
$(sed-i) 's|<script>|<script>\n<!-- inject -->|' \
45+
src/http/graphiql.html
46+
$(sed-i) '/X-Example-Header/d' \
47+
src/http/graphiql.html
48+
49+
50+
51+
52+
##################
53+
# .PHONY section #
54+
##################
55+
56+
.PHONY: graphiql

juniper/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"private": true,
3+
"scripts": {
4+
"postinstall": "make graphiql"
5+
},
6+
"dependencies": {
7+
"graphiql": "3.0.5"
8+
}
9+
}

juniper/src/http/graphiql.html

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<!--
2+
* Copyright (c) 2021 GraphQL Contributors
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
-->
8+
<!doctype html>
9+
<html lang="en">
10+
<head>
11+
<title>GraphiQL</title>
12+
<style>
13+
body {
14+
height: 100%;
15+
margin: 0;
16+
width: 100%;
17+
overflow: hidden;
18+
}
19+
20+
#graphiql {
21+
height: 100vh;
22+
}
23+
</style>
24+
25+
<!--
26+
This GraphiQL example depends on Promise and fetch, which are available in
27+
modern browsers, but can be "polyfilled" for older browsers.
28+
GraphiQL itself depends on React DOM.
29+
If you do not want to rely on a CDN, you can host these files locally or
30+
include them directly in your favored resource bundler.
31+
-->
32+
<script
33+
crossorigin
34+
src="https://unpkg.com/react@18/umd/react.development.js"
35+
></script>
36+
<script
37+
crossorigin
38+
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
39+
></script>
40+
<script
41+
src="https://unpkg.com/[email protected]/graphiql.min.js"
42+
type="application/javascript"
43+
></script>
44+
<script
45+
src="https://unpkg.com/@graphiql/plugin-explorer/dist/index.umd.js"
46+
crossorigin
47+
></script>
48+
<!--
49+
These two files can be found in the npm module, however you may wish to
50+
copy them directly into your environment, or perhaps include them in your
51+
favored resource bundler.
52+
-->
53+
<link rel="stylesheet" href="https://unpkg.com/[email protected]/graphiql.min.css" />
54+
</head>
55+
56+
<body>
57+
<div id="graphiql">Loading...</div>
58+
<script>
59+
<!-- inject -->
60+
const root = ReactDOM.createRoot(document.getElementById('graphiql'));
61+
const fetcher = GraphiQL.createFetcher({
62+
url: GRAPHQL_URL,
63+
subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)
64+
});
65+
const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin();
66+
root.render(
67+
React.createElement(GraphiQL, {
68+
fetcher,
69+
defaultEditorToolsVisibility: true,
70+
plugins: [explorerPlugin],
71+
}),
72+
);
73+
</script>
74+
</body>
75+
</html>

0 commit comments

Comments
 (0)