Skip to content

Commit 49ac57a

Browse files
Merge pull request #1152 from johnbiundo/biundo/subscriptions-fix
docs(subscription.md) correction re: subscription handler name
2 parents 32f42f2 + efab4dd commit 49ac57a

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

content/graphql/subscriptions.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ GraphQLModule.forRoot({
1616

1717
#### Code first
1818

19-
To create a subscription using the code first approach, we'll make use of the `@Subscription()` decorator and the `PubSub` class from the `graphql-subscriptions` package, which provides a simple **publish/subscribe API**.
19+
To create a subscription using the code first approach, we use the `@Subscription()` decorator and the `PubSub` class from the `graphql-subscriptions` package, which provides a simple **publish/subscribe API**.
2020

21-
The subscription handler takes care of **subscribing** to an event by calling `PubSub#asyncIterator`. This method takes a single argument, the `triggerName` which corresponds to an event topic name.
21+
The following subscription handler takes care of **subscribing** to an event by calling `PubSub#asyncIterator`. This method takes a single argument, the `triggerName`, which corresponds to an event topic name.
2222

2323
```typescript
2424
const pubSub = new PubSub();
@@ -33,8 +33,6 @@ export class AuthorResolver {
3333
}
3434
```
3535

36-
The current implementation also requires that the method handler name match the `triggerName`. That is, in the code sample above, the method name `commentAdded()` must match the `triggerName` passed in to `pubSub.asyncIterator('commentAdded')`.
37-
3836
> info **Hint** All decorators are exported from the `@nestjs/graphql` package, while the `PubSub` class is exported from the `graphql-subscriptions` package.
3937
4038
> warning **Note** `PubSub` is a class that exposes a simple `publish` and `subscribe API`. Read more about it [here](https://www.apollographql.com/docs/graphql-subscriptions/setup.html). Note that the Apollo docs warn that the default implementation is not suitable for production (read more [here](https://github.com/apollographql/graphql-subscriptions#getting-started-with-your-first-subscription)). Production apps should use a `PubSub` implementation backed by an external store (read more [here](https://github.com/apollographql/graphql-subscriptions#pubsub-implementations)).
@@ -47,7 +45,22 @@ type Subscription {
4745
}
4846
```
4947

50-
To publish the event, use the `PubSub#publish` method. This is often used within a mutation to trigger a client-side update when a part of the object graph has changed. For example:
48+
Note that subscriptions, by definition, return an object with a single top level property whose key is the name of the subscription. This name is either inherited from the name of the subscription handler method (i.e., `commentAdded` above), or is provided explicitly by passing an option with the key `name` as the second argument to the `@Subscription()` decorator, as shown below.
49+
50+
```typescript
51+
@Subscription(returns => Comment, {
52+
name: 'commentAdded',
53+
})
54+
addCommentHandler() {
55+
return pubSub.asyncIterator('commentAdded');
56+
}
57+
```
58+
59+
This construct produces the same SDL as the previous code sample, but allows us to decouple the method name from the subscription.
60+
61+
### Publishing
62+
63+
Now, to publish the event, we use the `PubSub#publish` method. This is often used within a mutation to trigger a client-side update when a part of the object graph has changed. For example:
5164

5265
```typescript
5366
@@filename(posts/posts.resolver)
@@ -57,11 +70,23 @@ async addComment(
5770
@Args('comment', { type: () => Comment }) comment: CommentInput,
5871
) {
5972
const newComment = this.commentsService.addComment({ id: postId, comment });
60-
pubSub.publish('commentAdded', newComment);
73+
pubSub.publish('commentAdded', { commentAdded: newComment });
6174
return newComment;
6275
}
6376
```
6477

78+
The `PubSub#publish` method takes a `triggerName` (again, think of this as an event topic name) as the first parameter, and an event payload as the second parameter. As mentioned, the subscription, by definition, returns a value and that value has a shape. Look again at the generated SDL for our `commentAdded` subscription:
79+
80+
```graphql
81+
type Subscription {
82+
commentAdded(): Comment!
83+
}
84+
```
85+
86+
This tells us that the subscription must return an object with a top-level property name of `commentAdded` that has a value which is a `Comment` object. The important point to note is that the shape of the event payload emitted by the `PubSub#publish` method must correspond to the shape of the value expected to return from the subscription. So, in our example above, the `pubSub.publish('commentAdded', {{ '{' }} commentAdded: newComment {{ '}' }})` statement publishes a `commentAdded` event with the appropriately shaped payload. If these shapes don't match, your subscription will fail during the GraphQL validation phase.
87+
88+
### Filtering subscriptions
89+
6590
To filter out specific events, set the `filter` property to a filter function. This function acts similar to the function passed to an array `filter`. It takes two arguments: `payload` containing the event payload (as sent by the event publisher), and `variables` taking any arguments passed in during the subscription request. It returns a boolean determining whether this event should be published to client listeners.
6691

6792
```typescript
@@ -74,6 +99,8 @@ commentAdded(@Args('title') title: string) {
7499
}
75100
```
76101

102+
### Mutating subscription payloads
103+
77104
To mutate the published event payload, set the `resolve` property to a function. The function receives the event payload (as sent by the event publisher) and returns the appropriate value.
78105

79106
```typescript
@@ -85,6 +112,8 @@ commentAdded() {
85112
}
86113
```
87114

115+
> warning **Note** If you use the `resolve` option, you should return the unwrapped payload (e.g., with our example, return a `newComment` object directly, not a `{{ '{' }} commentAdded: newComment {{ '}' }}` object).
116+
88117
If you need to access injected providers (e.g., use an external service to validate the data), use the following construction.
89118

90119
```typescript

0 commit comments

Comments
 (0)