Implementation here.
In this example, the backend provides a query for a door's current state as well as a subscription to the changes:
type Door {
open: Boolean!
last_updated: AWSDateTime!
}
type Subscription {
door: Door
}
type Query {
door: Door!
}
The door has two fields: open
that shows whether it's open or not, and last_updated
that tracks when its status last changed. Tracking the last updated time is important: this provides a way for the client to decide which event is more current if it receives conflicting updates.
On the client side, we'll show the status of the door and when it was last changed:
We'll write a function that returns an RxJs observable and implements the necessary logic to emit only the values the client needs to show.
Its usage is:
updates({
opened: () => setSubscriptionStatus(true),
closed: () => setSubscriptionStatus(false),
}).subscribe((e) => setDoor(e));
The opened
and the closed
callbacks are to track the subscription status. Then the subscribe
handles new items as they come.
Diving one layer deeper, the updates
function defines how to make a subscription, how to query for the current state, and how to process items:
const updates = (listeners) => updatesToDoor(connection)({
getAuthorizationHeaders: () => ({
host: new URL(APIURL).host,
"x-api-key": APIKEY,
}),
subscription: {
query: `subscription MySubscription {
door {
open
last_updated
}
}
`,
variables: {},
extractItemFromSubscription: (item) => item.data.door,
},
fetchItem,
extractLastUpdated: (item) => new Date(item.last_updated),
listeners,
});