Skip to content

Commit

Permalink
Improve subscription examples
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesbayly committed Apr 22, 2024
1 parent 85a8730 commit ae8b04c
Showing 1 changed file with 91 additions and 91 deletions.
182 changes: 91 additions & 91 deletions docs/indexer/run_publish/query/subscription.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ The body of the entity in your query indicates what data you want to receive via
- `mutation_type`: The action that has been made to this entity. Mutation types can be either `INSERT`, `UPDATE` or `DELETE`.
- `_entity`: the value of the entity itself in JSON format.

::: warning Important
Please note that you must enable the `--subscription` flag on both the node and query service in order to use these functions.
:::

## Filtering

We also support filter on subscriptions, which means a client should only receive updated subscription data if that data or mutation meets certain criteria.
Expand Down Expand Up @@ -67,90 +71,23 @@ subscription {

Note that the `mutation` filter can be one of `INSERT`, `UPDATE` or `DELETE`.

## Examples

## Server-side Implementation with Apollo Server
First, let's set up the server-side. This includes defining the subscription type, event type, setting up a publish/subscribe mechanism (using `PubSub` from `graphql-subscriptions`), and adding a resolver for the subscription.

Below is the basic, minimal example in Node.js. Refer to the official documentation for other supported technologies (for example, [Kotlin](https://www.apollographql.com/docs/kotlin/essentials/subscriptions) or [Swift](https://www.apollographql.com/docs/ios/tutorial/tutorial-subscriptions/))

```javascript
const { ApolloServer, gql, PubSub } = require('apollo-server');
const pubsub = new PubSub();

// GraphQL type definitions
const typeDefs = gql`
type Balances {
id: ID!
amount: Int!
}
type BalanceUpdate {
id: ID!
mutation_type: String!
_entity: String!
amount: Int!
}
type Subscription {
balances(id: ID!, mutation: String!): BalanceUpdate
}
`;

// Resolvers define the technique for fetching the types defined in the schema
const resolvers = {
Subscription: {
balances: {
subscribe: (_, { id, mutation }) => {
const channel = `${mutation}_${id}`;
return pubsub.asyncIterator(channel);
},
},
},
};

// Create the Apollo Server instance
const server = new ApolloServer({ typeDefs, resolvers });

// Start the server
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
```
### Client-side (React Exampel)

You would need to have the logic to publish events to this subscription, typically in your mutation resolvers or anywhere the balance changes.
In the following client-side example, we will be using React and Apollo Client. We'll create a component that subscribes to the balance updates for a specific account.

Example publishing event:

```javascript

// Somewhere in your balance update business logic...
pubsub.publish(`UPDATE_${accountId}`, {
balances: {
id: accountId,
mutation_type: 'UPDATE',
_entity: 'Balances',
amount: newBalance, // assume newBalance is the updated balance
}
});
```

Note that this example does not include error handling or authentication/authorization, which are essential for production applications.

### Client-side Implementation with React and Apollo Client

Now, let's move on to the client side where we will be using React and Apollo Client. We'll create a component that subscribes to the balance updates for a specific account.

First, ensure your project has the required dependencies:
First, ensure your project has the required dependencies:

```bash
npm install @apollo/client graphql
```

Then, you can create a React component like this:

```javascript
import React, { useEffect } from 'react';
import { useSubscription, gql } from '@apollo/client';
```ts
import React, { useEffect } from "react";
import { useSubscription, gql } from "@apollo/client";

const BALANCES_SUBSCRIPTION = gql`
subscription BalancesSubscription($id: ID!, $mutation: String!) {
Expand All @@ -170,7 +107,7 @@ const BalanceUpdates = ({ accountId }) => {

useEffect(() => {
if (data) {
console.log('Received data:', data);
console.log("Received data:", data);
}
}, [data]);

Expand All @@ -188,50 +125,113 @@ const BalanceUpdates = ({ accountId }) => {
export default BalanceUpdates;
```

This React component uses `useSubscription` from Apollo Client to subscribe to the balance updates. Make sure your Apollo Client is properly configured to connect to your GraphQL server, and it supports WebSocket for subscriptions.
This React component uses `useSubscription` from Apollo Client to subscribe to the balance updates. Make sure your Apollo Client is properly configured to connect to your GraphQL server, and it supports WebSocket for subscriptions. See more docs about Apollo Client [here](https://www.apollographql.com/docs/react/)

To connect to the server, typically, you would set up `ApolloClient` with something like this:

```javascript
import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import { ApolloClient, InMemoryCache, HttpLink, split } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";

const httpLink = new HttpLink({
uri: 'http://your-server.com/graphql',
uri: "http://your-server.com/graphql",
});

const wsLink = new WebSocketLink({
uri: 'ws://your-server.com/graphql',
uri: "ws://your-server.com/graphql",
options: {
reconnect: true
}
reconnect: true,
},
});

const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
httpLink,
httpLink
);

const client = new ApolloClient({
link: splitLink,
cache: new InMemoryCache()
cache: new InMemoryCache(),
});

```

This setup uses HTTP for queries and mutations, and WebSocket for subscriptions, switching automatically based on the operation type. For production readiness, consider adding logic in the client component to handle unsubscription or cleanup when the component unmounts or when the user navigates away.

::: warning Important
Please note that you must enable the `--subscription` flag on both the node and query service in order to use these functions.
:::
### Server-side (Apollo Server)

In this examplle, we will use `PubSub` from `graphql-subscriptions` for setting up a publish/subscribe mechanism, and add a resolver for the subscription.

Below is the basic, minimal example in [Node.js](https://www.apollographql.com/docs/apollo-server). Refer to the official documentation for other supported technologies (for example, [Kotlin](https://www.apollographql.com/docs/kotlin/essentials/subscriptions) or [Swift](https://www.apollographql.com/docs/ios/tutorial/tutorial-subscriptions/))

```javascript
const { ApolloServer, gql, PubSub } = require("apollo-server");
const pubsub = new PubSub();

// GraphQL type definitions
const typeDefs = gql`
type Balances {
id: ID!
amount: Int!
}
type BalanceUpdate {
id: ID!
mutation_type: String!
_entity: String!
amount: Int!
}
type Subscription {
balances(id: ID!, mutation: String!): BalanceUpdate
}
`;

// Resolvers define the technique for fetching the types defined in the schema
const resolvers = {
Subscription: {
balances: {
subscribe: (_, { id, mutation }) => {
const channel = `${mutation}_${id}`;
return pubsub.asyncIterator(channel);
},
},
},
};

// Create the Apollo Server instance
const server = new ApolloServer({ typeDefs, resolvers });

// Start the server
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
```

You would need to have the logic to publish events to this subscription, typically in your mutation resolvers or anywhere the balance changes.

Example publishing event:

```ts
// Somewhere in your balance update business logic...
pubsub.publish(`UPDATE_${accountId}`, {
balances: {
id: accountId,
mutation_type: "UPDATE",
_entity: "Balances",
amount: newBalance, // assume newBalance is the updated balance
},
});
```

Note that this example does not include error handling or authentication/authorization, which are essential for production applications.

## Using in the Managed Service

Expand Down

0 comments on commit ae8b04c

Please sign in to comment.