GraphQL Subscriptions in Cloud Supergraphs
Real-time data delivery across your services
Cloud supergraph support for GraphQL subscriptions is currently in preview.
You can also use subscriptions with an Enterprise self-hosted supergraph. See the Apollo Router documentation.
Cloud supergraphs provide preview support for GraphQL subscription operations:
subscription OnStockPricesChanged {stockPricesChanged {symbolprice}}
With a cloud supergraph, you can add Subscription
fields to the schema of any subgraph that supports the graphql-transport-ws
WebSocket protocol:
type Subscription {stockPricesChanged: [Stock!]!}
Clients can then execute subscriptions on your cloud router, which executes them on your subgraphs.
ⓘ NOTE
To use subscriptions with your cloud supergraph, you must first complete certain prerequisites.
What are subscriptions for?
GraphQL subscriptions enable clients to receive continual, real-time updates whenever new data becomes available. Unlike queries and mutations, subscriptions are long-lasting. That means a client can receive multiple updates from a single subscription:
Subscriptions are best suited to apps that rely on frequently changing, time-sensitive data such as stock prices, IoT sensor readings, live chat, or sports scores.
How subscriptions work
A client executes a GraphQL subscription operation against your router over HTTP:
Example subscriptionsubscription OnStockPricesChanged {stockPricesChanged {symbolprice}}- The client doesn't use a WebSocket protocol. Instead, it receives updates via multipart HTTP responses.
- By using HTTP for subscriptions, clients can execute all GraphQL operation types over HTTP instead of using two different protocols.
- Apollo Client, Apollo Kotlin, and Apollo iOS all support GraphQL subscriptions over HTTP with minimal configuration. See each library's documentation for details. Apollo Client also provides network adapters for the Relay and urql libraries.
When your router receives a subscription, it executes that same subscription against whichever subgraph defines the requested field—
stockPricesChanged
in the code snippet above.- This communication usually does use a WebSocket subprotocol, for compatibility with most subgraph libraries.
- With a self-hosted router, you can also configure an HTTP-callback-based protocol.
The subgraph periodically sends new data to your router. Whenever it does, the router returns that data to the client in an additional HTTP response part.
- A subscription can include federated entity fields that are defined in other subgraphs. If it does, the router first fetches those fields by querying the corresponding subgraphs, such as the Portfolios subgraph in the diagram above. These queries use HTTP as usual.
Prerequisites
Before you add Subscription
fields to your subgraphs, do all the following in the order shown to prevent errors:
Make sure you've created a cloud supergraph and connected your GraphQL API to it!
Update your supergraph's build pipeline to use Apollo Federation 2.4 or later.
- Previous versions of Apollo Federation don't support subscription operations.
If your subgraph schemas specify an Apollo Federation version, modify them to use Apollo Federation 2.4 or later:
stocks.graphqlextend schema@link(url: "https://specs.apollo.dev/federation/v2.4"import: ["@key", "@shareable"])type Subscription {stockPricesChanged: [Stock!]!}- You can skip modifying subgraph schemas that don't define any
Subscription
fields.
- You can skip modifying subgraph schemas that don't define any
In each subgraph with subscriptions, make sure the subgraph uses the
graphql-transport-ws
WebSocket protocol for subscriptions.In each subgraph with subscriptions, make sure the subgraph hosts its subscriptions WebSocket endpoint at the path
/ws
.- If your WebSocket endpoint is currently hosted at a different path, you can add
/ws
as an additional path instead of removing the original path. This is helpful if legacy clients will continue executing subscriptions on your subgraph directly using the original path.
- If your WebSocket endpoint is currently hosted at a different path, you can add
Deploy your updated subgraphs.
After you complete these prerequisites, you begin executing subscriptions on your cloud router.
Default configuration
Subscriptions are enabled automatically for GraphOS Cloud with the following default router configuration:
subscription:enabled: truemode:passthrough:all:path: /ws
Example execution
Let's say our supergraph includes the following subgraphs and partial schemas:
type Product @key(fields: "id") {id: ID!name: String!price: Int!}type Subscription {productPriceChanged: Product!}
type Product @key(fields: "id") {id: ID!reviews: [Review!]!}type Review {score: Int!}
A client can execute the following subscription against our router:
ⓘ NOTE
Remember, clients execute subscriptions against your router over HTTP!
Apollo Client for Web, Kotlin, and iOS all support HTTP-based subscriptions.
subscription OnProductPriceChanged {productPriceChanged {# Defined in Products subgraphnamepricereviews {# Defined in Reviews subgraph!score}}}
When our router receives this operation, it executes a corresponding subscription operation against the Products subgraph (over a new WebSocket connection):
subscription {productPriceChanged {id # Added for entity fetchingnameprice# Reviews fields removed!}}
ⓘ NOTE
- This operation adds the
Product.id
field. The router needs@key
fields of theProduct
entity to merge entity fields from across subgraphs. - This operation removes all fields defined in the Reviews subgraph, because the Products subgraph can't resolve them.
At any point after the subscription is initiated, the Products subgraph might send updated data to our router. Whenever this happens, the router does not immediately return this data to the client, because it's missing requested fields from the Reviews subgraph!
Instead, our router executes a standard GraphQL query against the Reviews subgraph to fetch the missing entity fields:
query {_entities(representations: [...]) {... on Product {reviews {score}}}}
After receiving this query result from the Reviews subgraph, our router combines it with the data from Products and returns the combination to the subscribing client.
Trying subscriptions with curl
To quickly try out HTTP-based subscriptions without setting up an Apollo Client library, you can execute a curl
command against your cloud router with the following format:
curl 'https://main--my-org-supergraph.apollographos.net/graphql' -v \-H 'accept: multipart/mixed; boundary="graphql"; subscriptionSpec=1.0, application/json' \-H 'content-type: application/json' \--data-raw '{"query":"subscription OnProductPriceChanged { productPriceChanged { name price reviews { score } } }","operationName":"OnProductPriceChanged"}'
This command creates an HTTP multipart request and keeps an open connection that receives new subscription data in multiple response parts:
--graphqlcontent-type: application/json{}--graphqlcontent-type: application/json{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":400,"reviews":[{"score":5}]}}}}--graphqlcontent-type: application/json{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":375,"reviews":[{"score":5}]}}}}--graphqlcontent-type: application/json{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":425,"reviews":[{"score":5}]}}}}--graphql--
ⓘ NOTE
This example subscription only emits three events and then directly closes the connection.
For more information on this multipart HTTP subscription protocol, see this article.