# Source: https://docs.hypermode.com/dgraph/graphql/subscriptions.md

# Subscriptions

> Subscriptions allow clients to listen to real-time messages from the server. In GraphQL, it's straightforward to enable subscriptions on any type.

<Info>
  We're overhauling Dgraph's docs to make them clearer and more approachable. If
  you notice any issues during this transition or have suggestions, please
  [let us know](https://github.com/hypermodeinc/docs/issues).
</Info>

Subscriptions allow clients to listen to real-time messages from the server. The
client connects to the server with a bi-directional communication channel using
the WebSocket protocol and sends a subscription query that specifies which event
it's interested in. When an event is triggered, the server executes the stored
GraphQL query, and the result is sent back to the client using the same
communication channel.

The client can unsubscribe by sending a message to the server. The server can
also unsubscribe at any time due to errors or timeouts. A significant difference
between queries or mutations and subscriptions is that subscriptions are
stateful and require maintaining the GraphQL document, variables, and context
over the lifetime of the subscription.

<img src="https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=7fb07bf0420ccf973f2e8aadecb7073c" alt="Subscription" width="476" height="472" data-path="images/dgraph/graphql/subscription_flow.png" srcset="https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=280&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=2b9fcd6345c7527b0813487d8c570402 280w, https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=560&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=0eac53047899f4312d1c30befa994618 560w, https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=840&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=c5063dd8d31ff47420df775eb000659c 840w, https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=1100&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=b80da011caaf7316e5572277d4eea597 1100w, https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=1650&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=b3c38f30e185d4177d22238632d867ca 1650w, https://mintcdn.com/hypermode/mx5jPijweyuId04r/images/dgraph/graphql/subscription_flow.png?w=2500&fit=max&auto=format&n=mx5jPijweyuId04r&q=85&s=facb27a4026c47a9722d3387003b019f 2500w" data-optimize="true" data-opv="2" />

## Enable subscriptions in GraphQL

In GraphQL, it's straightforward to enable subscriptions on any type. You can
add the `@withSubscription` directive to the schema as part of the type
definition, as in the following example:

```graphql
type Todo @withSubscription {
  id: ID!
  title: String!
  description: String!
  completed: Boolean!
}
```

## `@withSubscription` with `@auth`

You can use [@auth](/dgraph/graphql/schema/directives/auth) access control rules
in conjunction with `@withSubscription`.

Consider following Schema that has both the `@withSubscription` and `@auth`
directives defined on type `Todo`.

```graphql
type Todo
  @withSubscription
  @auth(
    query: {
      rule: """
      query ($USER: String!) {
        queryTodo(filter: { owner: { eq: $USER } } ) {
          __typename
        }
      }
      """
    }
  ) {
  id: ID!
  text: String! @search(by: [term])
  owner: String! @search(by: [hash])
}
# Dgraph.Authorization {"Header":"X-Dgraph-AuthToken","Namespace":"https://dgraph.io/jwt/claims","jwkurl":"https://xyz.clerk.accounts.dev/.well-known/jwks.json","audience":["dgraph"],"ClosedByDefault":true}
```

The generated GraphQL API expects a JWT token in the `X-Dgraph-AuthToken` header
and uses the `USER` claim to apply a Role-based Access Control (RBAC). The
authorization rule enforces that only to-do tasks owned by `$USER` are returned.

## WebSocket client

Dgraph uses the WebSocket protocol `subscription-transport-ws`.

Clients must be instantiated using the WebSocket URL of the GraphQL API which is
your
[Dgraph GraphQL endpoint](dgraph/graphql/connecting#getting-your-graphql-endpoint)
with `https` replaced by `wss`.

If your Dgraph endpoint is `https://<path>` the WebSocket URL is `wss://<path>`

If your GraphQL API is configured to expect a JWT token in a header, you must
configure the WebSocket client to pass the token. Additionally, the subscription
terminates when the JWT expires.

Here are some examples of frontend clients setup.

### Urql client setup in a React app

In this scenario, we're using the
[urql client](https://formidable.com/open-source/urql/) and
`subscriptions-transport-ws` modules.

In order to use a GraphQL subscription query in a component, you need to

* instantiate a `subscriptionClient`
* instantiate a urql client with a `subscriptionExchange` using the
  `ubscriptionClient`

```js
import {
  Client,
  Provider,
  cacheExchange,
  fetchExchange,
  subscriptionExchange,
} from "urql"
import { SubscriptionClient } from "subscriptions-transport-ws"

const subscriptionClient = new SubscriptionClient(
  process.env.REACT_APP_DGRAPH_WSS,
  { reconnect: true, connectionParams: { "X-Dgraph-AuthToken": props.token } },
)

const client = new Client({
  url: process.env.REACT_APP_DGRAPH_ENDPOINT,
  fetchOptions: { headers: { "X-Dgraph-AuthToken": `Bearer ${props.token}` } },
  exchanges: [
    cacheExchange,
    fetchExchange,
    subscriptionExchange({
      forwardSubscription: (request) => subscriptionClient.request(request),
    }),
  ],
})
```

In this example,

* `process.env.REACT_APP_DGRAPH_ENDPOINT` is your
  [Dgraph GraphQL endpoint](dgraph/graphql/connecting#getting-your-graphql-endpoint)
* `process.env.REACT_APP_DGRAPH_WSS` is the WebSocket URL
* `props.token` is the JWT token of the logged-in user.

Note that we pass the JWT token in the GraphQL client using `fetchOptions` and
in the WebSocket client using `connectionParams`.

Assuming we use graphql-codegen, we can define a subscription query:

```js
import { graphql } from "../gql"

export const TodoFragment = graphql(`
  fragment TodoItem on Todo {
    id
    text
  }
`)

export const TodoSubscription = graphql(`
  subscription myTodo {
    queryTodo(first: 100) {
      ...TodoItem
    }
  }
`)
```

and use it in a React component

```js
import { useQuery, useSubscription } from "urql";
...
const [messages] = useSubscription({ query: MyMessagesDocument});

```

That's it, the react component is able to use `messages.data.queryTodo` to
display the updated list of to dos.

### Apollo client setup

To learn about using subscriptions with Apollo client, see a blog post on
[GraphQL Subscriptions with Apollo client](https://hypermode.com/blog/post/how-does-graphql-subscription/).

To pass the user JWT token in the Apollo client,use `connectionParams`, as
follows.

```javascript
const wsLink = new WebSocketLink({
  uri: `wss://${ENDPOINT}`,
  options: {
    reconnect: true,
    connectionParams: {  "<header>": "<token>", },});
```

Use the header expected by the `Dgraph.Authorization` configuration of your
GraphQL schema.

## Subscriptions to custom DQL

You can also apply `@withSubscription` directive to custom DQL queries by
specifying `@withSubscription` on individual DQL queries in `type Query`, and
those queries are added to `type subscription`.

For example, see the custom DQL query `queryUserTweetCounts` below:

```graphql
type Query {
  queryUserTweetCounts: [UserTweetCount]
    @withSubscription
    @custom(
      dql: """
      query {
        queryUserTweetCounts(func: type(User)) {
          screen_name: User.screen_name
          tweetCount: count(User.tweets)
        }
      }
      """
    )
}
```

`queryUserTweetCounts` is added to the `subscription` type, allowing users to
subscribe to this query.

<Note>
  Currently, Dgraph only supports subscriptions on custom **DQL queries**. You
  can't subscribe to custom **HTTP queries**.
</Note>

<Note>
  Starting in release v21.03, Dgraph supports compression for subscriptions.
  Dgraph uses `permessage-deflate` compression if the GraphQL client's
  `Sec-Websocket-Extensions` request header includes `permessage-deflate`, as
  follows: `Sec-WebSocket-Extensions: permessage-deflate`.
</Note>