Dec 11, 2019· 8 mins to read

Building Real time API using graphql subscriptions easily


Building Real time API using graphql subscriptions easily

In this article, we will see how to build a real time api using graphQL Subscriptions. Building Real time API using graphql subscriptions easily.

If you are new to GraphQL, read this article to get the concepts of GraphQL before reading further.

We all know that web sockets are the important concepts nowadays which is widely used in many real time applications. Using that,we can able to build a real time API’s.

But wait, we have been using web sockets with REST API design. how can we use it in the GraphQL.

There’s comes the concept of GraphQL Subscriptions. GraphQL subscriptions is used to build a real time communication in the application.

Why we need that?

we can still use web sockets connections in web applications. the problem with web sockets (As far as i know and faced in production) is, it is hard to maintain when it scales. you have to open a socket in your front end and backend of your applications.

Also, you have to close it properly to avoid the load in server. there are few cases like this.

On the other hand, GraphQL is completely abstacted one where developer can easily manage the subscription. it will take care of all the technical difficulties.

It is similar to how you define and use Queries and Mutations in GraphQL.

Okay..Enough of this theory. it’s time to implement in a Nodejs Application.

Implementing Subscription in Nodejs Application

Let’ see how to implement GraphQL Subscription in Node.js. I Assume that you have some experience in using babel setup in node.js application.

If not, you can read this article to get good grasp of it. we are going to implement a simple api to understand the concept of GraphQL subscriptions.

GraphQL Subscriptions Logical WorkFlow

graphql subscriptions

Firslty, setup the express graphql boilerplate referring this article. create app.js and add the following code

import express from "express";
import bodyParser from "body-parser";
import { ApolloServer, gql } from "apollo-server-express";
import { merge } from "lodash";
import { createServer } from "http";
import cors from "cors";
const app = express();

app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

require("dotenv").config();

const schema = gql``;

const resolvers = {
  Query: {},
  Mutation: {},
  Subscription: {},
};

const server = new ApolloServer({
  typeDefs: schema,
  resolvers: resolvers,
  playground: {
    settings: {
      "editor.theme": "dark",
    },
  },
  context: {
    async({ req, connection }) {
      if (connection) {
        return connection.context;
      } else {
        return req;
      }
    },
  },
});

server.applyMiddleware({ app, path: "/graphql" });

const httpServer = createServer(app);
server.installSubscriptionHandlers(httpServer);

httpServer.listen(3005, () => {
  console.log(`Server is running on PORT 3005`);
});

Here, we have the basic set to run the GraphQL Express application. Let’s create a db connection and import it inside our app.js

const mongoose = require("mongoose");

class DB {
  constructor() {
    this._db = null;
    this.URL = process.env.MONGODB_URL;
  }
}

DB.prototype.initDB = function () {
  mongoose
    .connect(this.URL, { useNewUrlParser: true })
    .then((db) => {
      this._db = db;

      console.log(`DB is connected successfully`);
      return this._db;
    })
    .catch((err) => {
      throw new Error(err);
    });
};

DB.prototype.getDB = function () {
  if (this._db) {
    return this._db;
  } else {
    return this.initDB();
  }
};

module.exports = DB;

add the _db.js file inside the app.js

import DB from "./_db";

const _db = new DB();
_db.getDB();

After that, create a model file called postModel.js to use it inside the GraphQL resolver.

import Mongoose from "mongoose";

const postSchema = new Mongoose.Schema({
  title: {
    type: String,
  },
  body: {
    type: String,
  },
  createdUserId: {
    type: String,
  },
});

class Post {
  static getPostById(id) {
    return this.findOne({
      _id: id,
    }).exec();
  }

  static insertPost(postInfo) {
    const post = this(postInfo);

    return post.save();
  }
}

postSchema.loadClass(Post);

export default Mongoose.model("Post", postSchema);

Let’s create an Mutation to create a post. create a directory called postResolvers and add createPost.js file in it.

import PostModel from "../postModel";
export default async (parent, args, context) => {
  try {
    let postInfo = {
      title: args.request.title,
      body: args.request.body,
      createdUserId: args.request.createdUserId,
    };
    const postCollection = await PostModel.insertPost(postInfo);

    return {
      success: true,
      data: postCollection,
      error: null,
    };
  } catch (e) {
    return {
      success: false,
      data: null,
      error: {
        status: 500,
        message: e,
      },
    };
  }
};

Meanwhile, add the resolver inside app.js file and define schema for it.

const schema = gql`
  type Post {
    _id: ID
    title: String
    body: String
    createdUserId: String
  }

  input createPostInput {
    title: String
    body: String
    createdUserId: String
  }

  type createPostResponse {
    success: Boolean
    data: Post
    error: Error
  }

  type Error {
    status: Int
    message: String
  }

  type Query {
    hello: String
  }

  type Mutation {
    createPost(request: createPostInput!): createPostResponse!
  }
`;

After that, add the resolver in the apollo server

const resolvers = {
  Query: {},
  Mutation: {
    ...postResolvers,
  },
};

Now, it’s time to add the subscription to our application. just like query and resolver, we need to add a type definition and resolver for the subscription

add the type definition for subscription in the schema

type Subscription {
    postCreated: Post
  }

Like i said before, subscription work with the concepts of PubSub. if you are new to PubSub, read this article to know about it better.

basically, it is a publish-subscriber pattern where publisher publish an event with a message, subribers who subscribed to it will receive the message.

create a file to initialize the PubSub in the application

import { PubSub } from "apollo-server";

import * as PUBSUB_EVENTS from "./topics";
export const EVENTS = {
  TOPIC: PUBSUB_EVENTS,
};

export default new PubSub();

For the sake of maintanability, the event are separated and imported into the file.

create a file called topic.js and add the events,

export const POST_CREATED = "POST_CREATED";

After that, we need to add publish event to the mutation resolver. here, API(Mutation) is the publisher. Add the publish method inside the Mutation Resolver

pubsub.publish(EVENTS.TOPIC.POST_CREATED, {
  postCreated: { postCollection },
});

That’s it for the publishing events. Now, it is time to create Subscription inside resolvers,

add the following code inside resolvers

Subscription: {
  postCreated: {
    subscribe: () => {
      return pubsub.asyncIterator(EVENTS.TOPIC.POST_CREATED);
    };
  }
}

Demo

Finally, It’s time to test Subscriptions.. let’s do it :-)

Run the Server and Subscription before Mutation API call.

Subscription will by running asynchronously, once Mutation is successful. you can able to see the data in subscription tab.

https://youtu.be/AFoAMwsPrEw

Copyright © Cloudnweb. All rights reserved.