DEV Community

Novvum Dev Team for Novvum

Posted on

GraphQL Subscriptions with Nexus and React Apollo

Introduction

Subscriptions are a very powerful feature of GraphQL. They allow you to have a real-time connection to your database, notifying and updating your data when there are changes. Subscriptions have tons of applications, such as real-time chat applications or live comment feeds on articles.

In this tutorial, we are going to create a minimal real-time chat application using GraphQL Nexus and React Apollo. Hopefully by the end of this, you’ll be a pro at using subscriptions.

dev.to1

Meat and Potatoes

Getting Set Up

To get started, download this repository: https://github.com/hkyang995/graphql-nexus-subscription-starter-backend

This project contains a schema with a single 

Post type- Post has two fields, author and content. We will set up a subscription to update a live chat feed with every new post that is made.

If you take a peek at src/schema.ts, you’ll see two queries, 

post and posts. The post query returns the single most recent post, while posts returns every post in the database. And as you might have guessed, the createPost mutation creates a post.

Let’s get started by installing our tools: GraphQL Yoga, GraphQL Nexus, and GraphQL. We’ll be using Prisma’s demo servers to help get things set up and conveniently host all of our information. The starter file uses yarn to tie our dependencies together, so all we need to do is:

yarn

To start the server at any time during the tutorial, use:

yarn dev

Now that we’ve installed everything, we can create a server with Prisma using:

prisma init

This command will walk us through the creation of the server. Feel free to choose whatever suits your needs, but for simplicity’s sake, these options will do just fine:

  • Demo server
  • Choose EU or US
  • Name your shiny new service
  • Choose a name for this stage (just the default is fine)
  • Choose Typescript for our language of choice

Your server will be good to go after running prisma generate.

Now we’re finally ready to dive into making our Subscription!

Creating the Subscription on the Backend

Now that we are set up, we are ready to create our Subscription. Since each Subscription needs to return a payload (the bundle of information sent back to you), we’ll add a payload type to our schema.

const PostSubscriptionPayload = objectType({
 name: "PostSubscriptionPayload",
 definition(t) {
   t.field("node", {
     type: Post,
     nullable: true
   });
   t.list.string("updatedFields", { nullable: true });
 }
});

Like mentioned above, this payload type is the object type that will be returned from our subscription. The key item that we’re going to be looking at is t.field(“node”). We set its type to Post so it’ll return exactly what we need, a Post!

const messageSubscription = subscriptionField("post", {
 type: PostSubscriptionPayload,
 subscribe: (root, args, context) => {
   return context.prisma.$subscribe.post({ mutation_in: "CREATED" }) as any;
 },
 resolve: payload => {
   return payload;
 }
});

Here’s the function that’s going to be doing most of the work. You might be thinking, “That’s it??” and yes, that is it! You don’t need anything else on the backend for this particular application.

Here’s how this code works. We set the type to PostSubscriptionPayload to return our post. You can see that we pass in an argument to the post mutation_in: ‘CREATED’, which means that we’re only going to subscribe to newly created posts (as opposed to posts that are edited or deleted). Finally, we return the payload which completes our Subscription!

You can test this out on your GraphQL Playground by starting it up with yarn dev. When you run the Subscription, it will start listening for new posts. When you create a new post using the createPost mutation, you’ll be able to see it in your Subscription’s tab.

gif

You can check out and download the completed backend code here:

https://github.com/hkyang995/graphql-nexus-subscription-starter-backend/tree/completed

Creating the Subscription on the Frontend

We have our subscriptions working on the backend, but we’re not out of the woods yet. The next steps are to make subscriptions work on the frontend so we can see our shiny new Posts in real time.

To start out, let’s set up a simple UI and connect our frontend to the backend. To get started, download this repo of frontend code:

https://github.com/hkyang995/graphql-nexus-subscription-starter-frontend

To run the application at any time, use yarn start in the command line on the frontend folder.

const wsLink = new WebSocketLink({
 uri: `ws://localhost:4000/`,
 options: {
   reconnect: true
 }
});

const httpLink = createHttpLink({
 uri: "http://localhost:4000/"
});

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

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

If you take a look at src/App.js, you’ll see that we’re using Apollo to connect our frontend with our backend. The backend server is set to localhost:4000, which can be changed if your server is being hosted elsewhere. We’re also connecting a WebSocket to all of this so we are able to get our subscriptions in real time.

Most of the legwork is being done in our components function, src/AppContents.js. In this file, there is a function that takes the input and does a mutation to push the Post to our server. In src/ChatBox.js, we query for the Posts that already exist and display them to the user.

For now, we can write out messages and submit them, but the chat box won’t update unless we refresh. To fix this, we will set up our Subscription on the frontend.

Using one of our imported packages, graphql-tag (gql), we can set up a subscription on the frontend like this:

const NEW_POST_SUBSCRIPTION = gql`
 subscription PostSubscription {
   post {
     node {
       content
       id
       author
     }
   }
 }
`;

Since we defined our subscription on the backend, we only need to specify what we want to grab from it on the frontend. Here we’re getting the content, id, and author.

<Query query={GET_EXISTING_POSTS}>
               {({ subscribeToMore, loading, error, data }) => {

The subscribeToMore function comes packaged in Apollo GraphQL, and is going to be our best friend on the frontend, as it’s going to get our Subscriptions to work. We can pass it through in our query function.

<ChatView
  data={data}
  subscribeToMore={() =>
    subscribeToMore({
      document: NEW_POST_SUBSCRIPTION,
      updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) return prev;
        const { node } = subscriptionData.data.post;
        return Object.assign({}, prev, {
          posts: [...prev.posts, node]
        });
      }
    })
   }
/>

Here, we’re passing the subscribeToMore function into our ChatView component. Let’s break down how this all works.

We’re passing the subscription into the document field, and updateQuery is a function that runs every time our query is updated.

const { node } = subscriptionData.data.post;

We can pull out the node from the subscription data, which contains all of the information about the post: the content, the post id, and the author of the post.

return Object.assign({}, prev, {
  posts: [...prev.posts, node]
});

At the very end, we’re updating our posts by setting it equal to its previous values, along with the new node we got from the subscription.

  componentDidMount() {
    this.props.subscribeToMore();
  }

The last thing we need to do is add the subscribeToMore function into the ChatView component’s componentDidMount function. This will allow it to update whenever it needs to.

And there you have it! Now whenever a message is sent, your subscription will update the frontend.

The completed code can be found here.

https://github.com/hkyang995/graphql-nexus-subscription-starter-frontend/tree/completed

Conclusion

In this tutorial, we built a real-time chat application using GraphQL subscriptions. With this under your belt, subscriptions will appear less daunting for more complex applications.

If you have any questions, comments, concerns, or just want to tell me about your day, feel free to leave a comment. For more content like this, feel free to follow Novvum on Twitter. Thank you!

Top comments (0)