Docs
Launch GraphOS Studio

GraphQL subscriptions with a cloud supergraph

Real-time data delivery from across your services


Cloud supergraph support for GraphQL subscriptions is currently in preview.

You can also use subscriptions with an Enterprise self-hosted . See the Apollo Router documentation.

Cloud s provide preview support for GraphQL subscription s:

subscription OnStockPricesChanged {
stockPricesChanged {
symbol
price
}
}

With a cloud , you can add Subscription s to the of any that supports the graphql-transport-ws WebSocket protocol:

stocks.graphql
type Subscription {
stockPricesChanged: [Stock!]!
}

Clients can then execute subscriptions on your cloud , which executes them on your s.

⚠️ Important: To use subscriptions with your cloud , 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 s, subscriptions are long-lasting. This means a client can receive multiple updates from a single subscription:

GraphQL ClientCloud RouterInitiates subscriptionNew data availableSends new dataNew data availableSends new dataGraphQL ClientCloud Router

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 it works

Your infrastructure
GraphOS
Subscribes
over WebSocket
Can query for
entity fields
as needed
Subscribes
over HTTP
Stocks
subgraph
Portfolios
subgraph
Cloud
Router
Client
  1. A client executes a GraphQL subscription against your cloud over HTTP:

    Example subscription
    subscription OnStockPricesChanged {
    stockPricesChanged {
    symbol
    price
    }
    }
    • The client does not use a WebSocket protocol! Instead, it receives updates via multipart HTTP responses.
    • By using HTTP for subscriptions, clients can execute all GraphQL types over HTTP instead of using two different protocols.
    • Apollo Client for Web, Kotlin, and iOS all support GraphQL subscriptions over HTTP with minimal configuration. See each library's documentation for details.
  2. When your cloud receives a subscription, it executes that same subscription against whichever defines the requested (stockPricesChanged in the example above).

  3. The periodically sends new data to your . Whenever it does, the returns that data to the client in an additional HTTP response part.

    • A subscription can include federated entity s that are defined in other s. If it does, the first fetches those s by querying the corresponding s (such as Portfolios in the diagram above). These queries use HTTP as usual.

Prerequisites

⚠️ Before you add Subscription fields to your subgraphs, do all of the following in the order shown to prevent errors:

  1. Make sure you've created a cloud supergraph and connected your GraphQL API to it!

  2. Update your supergraph's build pipeline to use Apollo Federation 2.4 or later.

    • Previous versions of Apollo Federation don't support subscription s.
  3. If your s specify an Apollo Federation version, modify them to use Apollo Federation 2.4 or later:

    stocks.graphql
    extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.4",
    import: ["@key", "@shareable"])
    type Subscription {
    stockPricesChanged: [Stock!]!
    }
    • You can skip modifying s that don't define any Subscription s.
  4. In each with subscriptions, make sure the uses the graphql-transport-ws WebSocket protocol for subscriptions.

  5. In each with subscriptions, make sure the 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 directly using the original path.
  6. Deploy your updated s.

After you complete these prerequisites, you begin executing subscriptions on your cloud .

Example execution

Let's say our includes the following s and partial s:

Products subgraph
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int!
}
type Subscription {
productPriceChanged: Product!
}
Reviews subgraph
type Product @key(fields: "id") {
id: ID!
reviews: [Review!]!
}
type Review {
score: Int!
}

A client can execute the following subscription against our :

⚠️ 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 subgraph
name
price
reviews {
# Defined in Reviews subgraph!
score
}
}
}

When our receives this , it executes a corresponding subscription against the Products (over a new WebSocket connection):

subscription {
productPriceChanged {
id # Added for entity fetching
name
price
# Reviews fields removed!
}
}

Note the following:

  • This adds the Product.id . The needs @key s of the Product entity to merge entity s from across s.
  • This removes all s defined in the Reviews , because the Products can't resolve them.

At any point after the subscription is initiated, the Products might send updated data to our . Whenever this happens, the does not immediately return this data to the client, because it's missing requested s from the Reviews !

Instead, our executes a standard GraphQL query against the Reviews to fetch the missing entity s:

query {
_entities(representations: [...]) {
... on Product {
reviews {
score
}
}
}
}

After receiving this query result from the Reviews , our 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 with the following format:

Example curl request
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--

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.

Previous
Using @defer
Next
Platform API
Edit on GitHubEditForumsDiscord