Skip to content

Commit

Permalink
Incorporate feedback from martijnwalraven
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephen Barlow committed Feb 1, 2021
1 parent 24149a4 commit 7563e3d
Showing 1 changed file with 22 additions and 19 deletions.
41 changes: 22 additions & 19 deletions docs/source/data/subscriptions.mdx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
---
title: Subscriptions
description: Persistent GraphQL operations
description: Persistent GraphQL read operations
---

import {ExpansionPanel} from 'gatsby-theme-apollo-docs';

> **Subscriptions are not supported in [Apollo Federation](https://www.apollographql.com/docs/federation/).**
> **Subscriptions are not currently supported in [Apollo Federation](https://www.apollographql.com/docs/federation/).**
**Subscriptions** are GraphQL operations that maintain an active connection between client and server. This enables your server to _push_ updates to a subscription's result as they occur, instead of requiring your client to _poll_ for updates.
**Subscriptions** are long-lasting GraphQL read operations that can update their result whenever a particular server-side event occurs. Most commonly, updated results are _pushed_ from the server to subscribing clients. For example, a chat application's server might use a subscription to push newly received messages to all clients in a particular chat room.

Because subscriptions use persistent two-way communication, they usually use [the WebSocket protocol](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) instead of HTTP. To support this, Apollo Server lets you [set a subscription-specific endpoint](#setting-a-subscription-endpoint) that's separate from the default endpoint for queries and mutations.
Because subscription updates are usually pushed by the server (instead of polled by the client), they usually use [the WebSocket protocol](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) instead of HTTP. To support this, Apollo Server lets you [set a subscription-specific endpoint](#setting-a-subscription-endpoint) that's separate from the default endpoint for queries and mutations.

You can use subscriptions with the core `apollo-server` library, or with any of Apollo Server's supported [middleware integrations](#using-with-middleware-integrations).

> **Important:** Compared to queries and mutations, subscriptions are significantly more complex to implement. Before you begin, [confirm that your use case requires subscriptions](https://www.apollographql.com/docs/react/data/subscriptions/#when-to-use-subscriptions).
## Schema definition

You define your schema's supported subscriptions as fields of the `Subscription` type:
Your schema's `Subscription` type defines top-level fields that clients can subscribe to:

```graphql
type Subscription {
postCreated: Post
}
```

The `postCreated` subscription will update its value whenever a new `Post` is created on the backend, thus pushing the `Post` to subscribing clients.
The `postCreated` field will update its value whenever a new `Post` is created on the backend, thus pushing the `Post` to subscribing clients.

Clients can execute this subscription with a GraphQL string like this:
Clients can subscribe to the `postCreated` field with a GraphQL string like this:

```graphql
subscription PostFeed {
Expand All @@ -38,6 +38,8 @@ subscription PostFeed {
}
```

> Each subscription operation can subscribe to only _one_ field of the `Subscription` type.
## Setting a subscription endpoint

Because subscriptions use WebSocket instead of HTTP, Apollo Server uses a _second_ GraphQL endpoint specifically for subscriptions. This endpoint uses the `ws` protocol instead of `http`.
Expand All @@ -55,7 +57,7 @@ const server = new ApolloServer({

## Resolving a subscription

Resolvers for subscriptions differ from those for queries and mutations. Specifically, subscription resolvers are _objects_ that define a `subscribe` function:
Resolvers for `Subscription` fields differ from resolvers for fields of other types. Specifically, `Subscription` field resolvers are _objects_ that define a `subscribe` function:

```js:title=index.js
const resolvers = {
Expand All @@ -69,13 +71,14 @@ const resolvers = {
};
```

The `subscribe` function must return an object of type `AsyncIterable`, part of Apollo Server's pub/sub API (described below).
The `subscribe` function must return an object of type `AsyncIterator`, a standard interface for iterating over asynchronous results. In the example above, an `AsyncIterator` is generated by `pubsub.asyncIterator` (more on this below).


### The `PubSub` class

> The `PubSub` class is **not** recommended for production environments, because it's an in-memory event system that only supports a single server instance. After you get subscriptions working in development, we strongly recommend switching it out for a different subclass of the abstract [`PubSubEngine` class](https://github.com/apollographql/graphql-subscriptions/blob/master/src/pubsub-engine.ts). Recommended subclasses are listed in [Production `PubSub` libraries](#production-pubsub-libraries).
Apollo Server uses a **publish-subscribe** (**pub/sub**) model to track events that update active subscriptions. The [`graphql-subscriptions` library](https://github.com/apollographql/graphql-subscriptions) (included in every `apollo-server` package) provides the `PubSub` class to help you get started:
Apollo Server uses a **publish-subscribe** (**pub/sub**) model to track events that update active subscriptions. The [`graphql-subscriptions` library](https://github.com/apollographql/graphql-subscriptions) (included in every `apollo-server` package) provides the `PubSub` class as a basic in-memory event bus to help you get started:

```js
const { PubSub } = require('apollo-server');
Expand All @@ -101,11 +104,11 @@ pubsub.publish('POST_CREATED', {
* The first parameter is the name of the event label you're publishing to, as a string.
* _You don't need to register a label name before publishing to it._
* The second parameter is the payload associated with the event.
* _The payload's structure should match the structure that clients expect from the associated subscription's return type._
* _The payload should include whatever data is necessary for your resolvers to populate the associated `Subscription` field and its subfields._

When working with GraphQL subscriptions, you `publish` an event whenever a subscription's return value should be updated. One of the most common causes of such an update is a mutation.
When working with GraphQL subscriptions, you `publish` an event whenever a subscription's return value should be updated. One common cause of such an update is a mutation, but _any_ back-end logic might result in changes that should be `publish`ed.

For example, let's say our GraphQL API supports a `createPost` mutation:
As an example, let's say our GraphQL API supports a `createPost` mutation:

```graphql
type Mutation {
Expand Down Expand Up @@ -141,19 +144,19 @@ const resolvers = {
};
```

Next, we can listen for this event in our subscription's resolver.
Next, we can listen for this event in our `Subscription` field's resolver.

### Listening for events

An [`AsyncIterable`](https://github.com/apollographql/graphql-subscriptions/blob/master/src/pubsub-async-iterator.ts) object listens for events that are associated with a particular label (or set of labels) and adds them to a queue for processing. You create an `AsyncIterable` by calling the `asyncIterator` method of `PubSub`:
An [`AsyncIterator`](https://github.com/apollographql/graphql-subscriptions/blob/master/src/pubsub-async-iterator.ts) object listens for events that are associated with a particular label (or set of labels) and adds them to a queue for processing. You create an `AsyncIterator` by calling the `asyncIterator` method of `PubSub`:

```js
pubsub.asyncIterator(['POST_CREATED']);
```

You pass this method an array containing the names of all event labels that the `AsyncIterable` should listen for.
You pass this method an array containing the names of all event labels that the `AsyncIterator` should listen for.

Every subscription resolver's `subscribe` function must return an `AsyncIterable` object. This brings us back to the code sample at the top of [Resolving a subscription](#resolving-a-subscription):
Every `Subscription` field resolver's `subscribe` function must return an `AsyncIterator` object. This brings us back to the code sample at the top of [Resolving a subscription](#resolving-a-subscription):

```js:title=index.js
const resolvers = {
Expand All @@ -166,11 +169,11 @@ const resolvers = {
};
```

With this `subscribe` function set, Apollo Server uses the payloads of `POST_CREATED` events to push updated field values for the `postCreated` subscription.
With this `subscribe` function set, Apollo Server uses the payloads of `POST_CREATED` events to push updated values for the `postCreated` field.

### Filtering events

Sometimes, a client should only receive updated subscription data if that data meets certain criteria. To support this, you can call the `withFilter` helper function in your subscription's resolver.
Sometimes, a client should only receive updated subscription data if that data meets certain criteria. To support this, you can call the `withFilter` helper function in your `Subscription` field's resolver.

#### Example

Expand Down

0 comments on commit 7563e3d

Please sign in to comment.