Skip to content

Commit 47f7ffa

Browse files
authored
Add subscriptions support for GraphiQL (#619)
* Add subscriptions support on GraphiQL Addresses #501 BREAKING CHANGE: `juniper::http::graphiql::graphiql_source` now requires a second parameter BREAKING CHANGE: `juniper_hyper::graphiql` now requires a second parameter BREAKING CHANGE: `juniper_iron::GraphiQLHandler::new` now requires a second parameter BREAKING CHANGE: `juniper_rocket::graphiql_source` now requires a second parameter BREAKING CHANGE: `juniper_warp::graphiql_filter` now requires a second parameter * Add test where graphiql subscriptions endpoint is not None
1 parent f0ccc2e commit 47f7ffa

File tree

15 files changed

+117
-19
lines changed

15 files changed

+117
-19
lines changed

juniper/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ See [#419](https://github.com/graphql-rust/juniper/pull/419).
1818
- `SchemaType` is now public
1919
- This is helpful when using `context.getSchema()` inside of your field resolvers
2020

21+
- Support subscriptions in GraphiQL
22+
2123
See [#569](https://github.com/graphql-rust/juniper/pull/569).
2224

2325
## Breaking Changes
2426

2527
- `juniper::graphiql` has moved to `juniper::http::graphiql`
28+
- `juniper::http::graphiql::graphiql_source` now requies a second parameter for subscriptions
2629

2730
- remove old `graphql_object!` macro, rename `object` proc macro to `graphql_object`
2831

juniper/src/http/graphiql.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
//! Utility module to generate a GraphiQL interface
22
33
/// Generate the HTML source to show a GraphiQL interface
4-
pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
4+
///
5+
/// The subscriptions endpoint URL can optionally be provided. For example:
6+
///
7+
/// ```
8+
/// # use juniper::http::graphiql::graphiql_source;
9+
/// let graphiql = graphiql_source("/graphql", Some("ws://localhost:8080/subscriptions"));
10+
/// ```
11+
pub fn graphiql_source(
12+
graphql_endpoint_url: &str,
13+
subscriptions_endpoint_url: Option<&str>,
14+
) -> String {
15+
let subscriptions_endpoint = if let Some(sub_url) = subscriptions_endpoint_url {
16+
sub_url
17+
} else {
18+
""
19+
};
20+
521
let stylesheet_source = r#"
622
<style>
723
html, body, #app {
@@ -14,6 +30,10 @@ pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
1430
"#;
1531
let fetcher_source = r#"
1632
<script>
33+
if (usingSubscriptions) {
34+
var subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient(GRAPHQL_SUBSCRIPTIONS_URL, { reconnect: true });
35+
}
36+
1737
function graphQLFetcher(params) {
1838
return fetch(GRAPHQL_URL, {
1939
method: 'post',
@@ -33,9 +53,12 @@ pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
3353
}
3454
});
3555
}
56+
57+
var fetcher = usingSubscriptions ? window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLFetcher) : graphQLFetcher;
58+
3659
ReactDOM.render(
3760
React.createElement(GraphiQL, {
38-
fetcher: graphQLFetcher,
61+
fetcher,
3962
}),
4063
document.querySelector('#app'));
4164
</script>
@@ -53,16 +76,22 @@ pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
5376
<body>
5477
<div id="app"></div>
5578
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.js"></script>
79+
<script src="//unpkg.com/subscriptions-transport-ws@0.8.3/browser/client.js"></script>
80+
<script src="//unpkg.com/graphiql-subscriptions-fetcher@0.0.2/browser/client.js"></script>
5681
<script src="//cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
5782
<script src="//cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
5883
<script src="//cdn.jsdelivr.net/npm/graphiql@0.17.5/graphiql.min.js"></script>
5984
<script>var GRAPHQL_URL = '{graphql_url}';</script>
85+
<script>var usingSubscriptions = {using_subscriptions};</script>
86+
<script>var GRAPHQL_SUBSCRIPTIONS_URL = '{graphql_subscriptions_url}';</script>
6087
{fetcher_source}
6188
</body>
6289
</html>
6390
"#,
6491
graphql_url = graphql_endpoint_url,
6592
stylesheet_source = stylesheet_source,
66-
fetcher_source = fetcher_source
93+
fetcher_source = fetcher_source,
94+
graphql_subscriptions_url = subscriptions_endpoint,
95+
using_subscriptions = subscriptions_endpoint_url.is_some(),
6796
)
6897
}

juniper_hyper/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- Compatibility with the latest `juniper`.
44

5+
## Breaking Changes
6+
7+
- `juniper_hyper::graphiql` now requires a second parameter for subscriptions
8+
59
# [[0.5.2] 2019-12-16](https://github.com/graphql-rust/juniper/releases/tag/juniper_hyper-0.5.2)
610

711
- Compatibility with the latest `juniper`.

juniper_hyper/examples/hyper_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ async fn main() {
3131
let ctx = ctx.clone();
3232
async move {
3333
match (req.method(), req.uri().path()) {
34-
(&Method::GET, "/") => juniper_hyper::graphiql("/graphql").await,
34+
(&Method::GET, "/") => juniper_hyper::graphiql("/graphql", None).await,
3535
(&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
3636
juniper_hyper::graphql(root_node, ctx, req).await
3737
}

juniper_hyper/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,16 @@ async fn parse_post_req<S: ScalarValue>(
114114
.map_err(GraphQLRequestError::BodyJSONError)
115115
}
116116

117-
pub async fn graphiql(graphql_endpoint: &str) -> Result<Response<Body>, hyper::Error> {
117+
pub async fn graphiql(
118+
graphql_endpoint: &str,
119+
subscriptions_endpoint: Option<&str>,
120+
) -> Result<Response<Body>, hyper::Error> {
118121
let mut resp = new_html_response(StatusCode::OK);
119122
// XXX: is the call to graphiql_source blocking?
120-
*resp.body_mut() = Body::from(juniper::http::graphiql::graphiql_source(graphql_endpoint));
123+
*resp.body_mut() = Body::from(juniper::http::graphiql::graphiql_source(
124+
graphql_endpoint,
125+
subscriptions_endpoint,
126+
));
121127
Ok(resp)
122128
}
123129

juniper_iron/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- Compatibility with the latest `juniper`.
44

5+
## Breaking Changes
6+
7+
- `juniper_iron::GraphiQLHandler::new` now requires a second parameter for subscriptions
8+
59
# [[0.6.2] 2019-12-16](https://github.com/graphql-rust/juniper/releases/tag/juniper_iron-0.6.2)
610

711
- Compatibility with the latest `juniper`.

juniper_iron/examples/iron_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn main() {
2929
EmptyMutation::<Database>::new(),
3030
EmptySubscription::<Database>::new(),
3131
);
32-
let graphiql_endpoint = GraphiQLHandler::new("/graphql");
32+
let graphiql_endpoint = GraphiQLHandler::new("/graphql", None);
3333

3434
mount.mount("/", graphiql_endpoint);
3535
mount.mount("/graphql", graphql_endpoint);

juniper_iron/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ pub struct GraphQLHandler<
159159
/// Handler that renders `GraphiQL` - a graphical query editor interface
160160
pub struct GraphiQLHandler {
161161
graphql_url: String,
162+
subscription_url: Option<String>,
162163
}
163164

164165
/// Handler that renders `GraphQL Playground` - a graphical query editor interface
@@ -275,9 +276,10 @@ impl GraphiQLHandler {
275276
///
276277
/// The provided URL should point to the URL of the attached `GraphQLHandler`. It can be
277278
/// relative, so a common value could be `"/graphql"`.
278-
pub fn new(graphql_url: &str) -> GraphiQLHandler {
279+
pub fn new(graphql_url: &str, subscription_url: Option<&str>) -> GraphiQLHandler {
279280
GraphiQLHandler {
280281
graphql_url: graphql_url.to_owned(),
282+
subscription_url: subscription_url.map(|s| s.to_owned()),
281283
}
282284
}
283285
}
@@ -326,7 +328,10 @@ impl Handler for GraphiQLHandler {
326328
Ok(Response::with((
327329
content_type,
328330
status::Ok,
329-
juniper::http::graphiql::graphiql_source(&self.graphql_url),
331+
juniper::http::graphiql::graphiql_source(
332+
&self.graphql_url,
333+
self.subscription_url.as_deref(),
334+
),
330335
)))
331336
}
332337
}

juniper_rocket/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
- Compatibility with the latest `juniper`.
44
- Rocket integration does not require default features.
55

6+
## Breaking Changes
7+
8+
- `juniper_rocket::graphiql_source` now requires a second parameter for subscriptions
9+
610
# [[0.5.2] 2019-12-16](https://github.com/graphql-rust/juniper/releases/tag/juniper_rocket-0.5.2)
711

812
- Compatibility with the latest `juniper`.

juniper_rocket/examples/rocket_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscriptio
1111

1212
#[rocket::get("/")]
1313
fn graphiql() -> content::Html<String> {
14-
juniper_rocket::graphiql_source("/graphql")
14+
juniper_rocket::graphiql_source("/graphql", None)
1515
}
1616

1717
#[rocket::get("/graphql?<request>")]

0 commit comments

Comments
 (0)