GraphQL Subscriptions in Cloud Supergraphs
Real-time data delivery across your services
Cloud supergraphs provide preview support for GraphQL subscription operations:
1subscription OnStockPricesChanged {
2 stockPricesChanged {
3 symbol
4 price
5 }
6}
With a cloud supergraph, you can add Subscription
fields to the schema of any subgraph that supports the graphql-transport-ws
WebSocket protocol:
1type Subscription {
2 stockPricesChanged: [Stock!]!
3}
Clients can then execute subscriptions on your cloud router, which executes them on your subgraphs.
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:
GraphQLstocks.graphql1extend schema 2 @link( 3 url: "https://specs.apollo.dev/federation/v2.4" 4 import: ["@key", "@shareable"] 5 ) 6 7type Subscription { 8 stockPricesChanged: [Stock!]! 9}
You can skip modifying subgraph schemas that don't define any
Subscription
fields.
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.
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:
1subscription:
2 enabled: true
3 mode:
4 passthrough:
5 all:
6 path: /ws
Example execution
Let's say our supergraph includes the following subgraphs and partial schemas:
1type Product @key(fields: "id") {
2 id: ID!
3 name: String!
4 price: Int!
5}
6
7type Subscription {
8 productPriceChanged: Product!
9}
1type Product @key(fields: "id") {
2 id: ID!
3 reviews: [Review!]!
4}
5
6type Review {
7 score: Int!
8}
A client can execute the following subscription against our router:
1subscription OnProductPriceChanged {
2 productPriceChanged {
3 # Defined in Products subgraph
4 name
5 price
6 reviews {
7 # Defined in Reviews subgraph!
8 score
9 }
10 }
11}
When our router receives this operation, it executes a corresponding subscription operation against the Products subgraph (over a new WebSocket connection):
1subscription {
2 productPriceChanged {
3 id # Added for entity fetching
4 name
5 price
6 # Reviews fields removed!
7 }
8}
- 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:
1query {
2 _entities(representations: [...]) {
3 ... on Product {
4 reviews {
5 score
6 }
7 }
8 }
9}
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:
--graphql
content-type: application/json
{}
--graphql
content-type: application/json
{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":400,"reviews":[{"score":5}]}}}}
--graphql
content-type: application/json
{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":375,"reviews":[{"score":5}]}}}}
--graphql
content-type: application/json
{"payload":{"data":{"productPriceChanged":{"name":"Croissant","price":425,"reviews":[{"score":5}]}}}}
--graphql--