Subscriptions
Hive Gateway fully supports federated subscriptions and behaves just like Federation GraphQL subscriptions in Apollo Router.
Subgraphs providing subscriptions can communicate with Hive Gateway through one of the following protocols:
Example
We’ll implement two GraphQL Yoga federation services behaving as subgraphs. The “products” service exposes a subscription operation type for subscribing to product changes, while the “reviews” service simply exposes review stats about products.
The example is somewhat similar to Apollo’s documentation, except for that we use GraphQL Yoga here and significantly reduce the setup requirements.
Install dependencies
npm i graphql-yoga @apollo/subgraph graphql
Products service
import { createServer } from 'http'
import { parse } from 'graphql'
import { createYoga } from 'graphql-yoga'
import { buildSubgraphSchema } from '@apollo/subgraph'
import { resolvers } from './my-resolvers'
const typeDefs = parse(/* GraphQL */ `
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int!
}
type Subscription {
productPriceChanged: Product!
}
`)
const yoga = createYoga({ schema: buildSubgraphSchema([{ typeDefs, resolvers }]) })
const server = createServer(yoga)
server.listen(40001, () => {
console.log('Products subgraph ready at http://localhost:40001')
})
Reviews service
import { createServer } from 'http'
import { parse } from 'graphql'
import { createYoga } from 'graphql-yoga'
import { buildSubgraphSchema } from '@apollo/subgraph'
import { resolvers } from './my-resolvers'
const typeDefs = parse(/* GraphQL */ `
extend type Product @key(fields: "id") {
id: ID! @external
reviews: [Review!]!
}
type Review {
score: Int!
}
`)
const yoga = createYoga({ schema: buildSubgraphSchema([{ typeDefs, resolvers }]) })
const server = createServer(yoga)
server.listen(40002, () => {
console.log('Reviews subgraph ready at http://localhost:40002')
})
Start Gateway
After having generated a supergraph file supergraph.graphql
for the two subgraphs, either using
GraphQL Mesh or
Apollo Rover, simply run Hive Gateway without any
additional configuration!
hive-gateway supergraph supergraph.graphql
Subscribe
Let’s now subscribe to the product price changes by executing the following query:
subscription {
productPriceChanged {
# Defined in Products subgraph
name
price
reviews {
# Defined in Reviews subgraph
score
}
}
}
Hive Gateway will inteligently resolve all fields on subscription events and deliver you the complete result.
You can subscribe to the gateway through Server-Sent Events (SSE) (in JavaScript, using
EventSource or
graphql-sse). For the sake of brevity, we’ll subscribe using
curl
:
curl 'http://localhost:4000/graphql' \
-H 'accept: text/event-stream' \
-H 'content-type: application/json' \
--data-raw '{"query":"subscription OnProductPriceChanged { productPriceChanged { name price reviews { score } } }","operationName":"OnProductPriceChanged"}'
Subgraphs using WebSockets
If your subgraph uses WebSockets for subscriptions support (like with Apollo Server), Hive Gateway will need additional configuration pointing to the WebSocket server path on the subgraph.
And configure Hive Gateway to use the /subscriptions
path on the “products” subgraph for WebSocket
connections:
import { defineConfig, type WSTransportOptions } from '@graphql-hive/gateway'
export const gatewayConfig = defineConfig({
supergraph: 'supergraph.graphql',
transportEntries: {
// use "*.http" to apply options to all subgraphs with HTTP
'*.http': {
options: {
subscriptions: {
kind: 'ws',
location: '/subscriptions'
} satisfies WSTransportOptions
}
}
}
})
Now simply start Hive Gateway with:
hive-gateway supergraph
Downstream clients are still subscribing to Hive Gateway gateway through any supported subscriptions protocol, but upstream Hive Gateway will use long-living WebSocket connections to the “products” service.
Authorization
header
Hive Gatewayr can propagate the downstream client’s Authorization
header contents to the upstream
WebSocket connections through the
ConnectionInit
message payload.
import { defineConfig, type WSTransportOptions } from '@graphql-hive/gateway'
export const gatewayConfig = defineConfig({
supergraph: 'supergraph.graphql',
transportEntries: {
// use "*.http" to apply options to all subgraphs with HTTP
'*.http': {
options: {
subscriptions: {
kind: 'ws',
location: '/subscriptions',
options: {
connectionParams: {
token: '{context.headers.authorization}'
}
} satisfies WSTransportOptions
}
}
}
}
})
The contents of the payload will be available in graphql-ws
connectionParams:
{
"connectionParams": {
"token": "<CONTENTS_OF_AUTHORIZATION_HEADER>"
}
}
This is also what Apollo Router when propagating auth on WebSockets.
Subscriptions using HTTP Callback
If your subgraph uses HTTP Callback protocol for subscriptions, Hive Gateway will need additional configuration.
import { defineConfig, type HTTPCallbackTransportOptions } from '@graphql-hive/gateway'
export const gatewayConfig = defineConfig({
supergraph: 'supergraph.graphql',
// Setup Hive Gateway to listen for webhook callbacks, and emit the payloads through PubSub engine
webhooks: true,
transportEntries: {
// use "*.http" to apply options to all subgraphs with HTTP
'*.http': {
options: {
subscriptions: {
kind: 'http-callback',
options: {
// The gateway's public URL, which your subgraphs access, must include the path configured on the gateway.
public_url: 'http://localhost:4000/callback',
// The path of the router's callback endpoint
path: '/callback',
// Heartbeat interval to make sure the subgraph is still alive, and avoid hanging requests
heartbeat_interval: 5000
} satisfies HTTPCallbackTransportOptions
}
}
}
}
})
Closing active subscriptions on schema change
When the schema changes in Hive Gateway, all active subscriptions will be completed after emitting the following execution error:
{
"errors": [
{
"message": "subscription has been closed due to a schema reload",
"extensions": {
"code": "SUBSCRIPTION_SCHEMA_RELOAD"
}
}
]
}
This is also what Apollo Router when terminating subscriptions on schema update.