Real-time React app with GraphQL + Websocket

GraphQL started to be a great option for writing customizable API’s and combining multiple services into one single endpoint. The whole idea of having single endpoint but getting different combination of models is very attractive, especially for companies which are working with large scale multi-platform applications with different frontend/mobile developers and designers.

This is generally for making REST API’s, and for many cases that’s the way to go for making application backends. But what if you want to give more real time feel and look to your application UI or make subscription based data transfers for improving more efficient infrastructure.

Getting project ready 🚀

In this era of Webpack, React and other large JS frameworks it is important to have generically configured project for having scalable codebase.

Here is the combination that we are going to configure

  1. Node.js + GraphQL.js + Websocket Subscriptions + Express.js if we need some generic REST API functionality as well

  2. React.js + Apollo + Websocket Subscriptions Client

For me configuring backend first is a tradition, but generally it doesn’t matter.

Configuring Node.js backend

Let’s just make a basic setup for node.js application with NPM and minimum packages which are required (no junk!).

npm init
npm i --save graphql subscriptions-transport-ws express
touch index.js # making main file for Node server
touch schema.js # creating GraphQL schemas here

**NOTE: **if you want also ES2015 you need to configure Babel as well, there is a lot of articles and boilerplates around that, so skipping that part here.

After reading documentation and knowing what we need here is how looks like out index.js file

**import **{ Server } **from **'http';
**import **{ **SubscriptionServer **} **from **'subscriptions-transport-ws';
**import **{ execute, subscribe } **from **'graphql';
**import ***GraphHTTP ***from **'express-graphql';
**import **express **from **'express';
**import **{ *expressAuth*, *wsAuth *} **from **'./auth_jwt';

*// Getting base GraphQL Schema
***import **schema **from **'./schema';

*/** BASE Express server definition **/
***const **app = express();

*// main endpoint for GraphQL Express
*app.use('/api/ql', GraphHTTP({
  schema: schema,
  graphiql: **true**,
}));

*// Making plain HTTP server for Websocket usage
***const **server = Server(app);

*/** GraphQL Websocket definition **/
***SubscriptionServer**.create({
  schema,
  execute,
  subscribe,
}, {
  server: server,
  path: '/api/ws',
}, );


server.listen(4000, () => {
  ***console***.log('Server started here -> http://0.0.0.0:4000');
});

Now we have a server which is going to respond with the same GraphQL scheme, for both Websocket /api/ws and REST Express /api/ql .

Let’s make a basic GraphQL schema and export that from schema.js

**import **{
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString
} **from **'graphql';

**export default new **GraphQLSchema ({
  query: **new **GraphQLObjectType ({
    name: 'Query',
    fields: {
      message: {
        type: GraphQLString,
        resolve() { return 'Hello World!'; }
      }
    }
  })
});

I know, nothing fancy, but still you can get the point, and do more better for your project.

Just start a server and go to localhost:4000/api on your browser, and you will see GraphQL endpoint for getting message

Configuring React App

To get started with React app it is pretty easy and useful to make it with create-react-app CLI tool, which is just giving you a lot of preconfigured things!

create-react-app graphql-ws
cd graphql-ws
npm i --save graphql graphql-tag subscriptions-transport-ws react-apollo apollo-cache-inmemory apollo-client apollo-link-http

Most probably you will need React Router, Redux etc… But that’s a different story.

After making graphql-ws React app, configuration for having GraphQL Websocket connections looks like this in src/index.js file

**import **React **from **'react';
**import **ReactDOM **from **'react-dom';
**import **'./index.css';
**import **App **from **'./App';
**import **registerServiceWorker **from **'./registerServiceWorker';
**import **{ **ApolloProvider **} **from **'react-apollo';
**import **{ **InMemoryCache **} **from **'apollo-cache-inmemory';
**import **{**SubscriptionClient**} **from **'subscriptions-transport-ws';
**import ApolloClient from **'apollo-client';

*// Create WebSocket client
***const **WSClient = **new SubscriptionClient**(`ws://localhost:4000/api/ws`, {
  reconnect: **true**,
  connectionParams: {
    *// Connection parameters to pass some validations 
    // on server side during first handshake
  *}
});

**const **GraphQLClient = **new ApolloClient**({
  link: WSClient,
  cache: **new InMemoryCache**()
});

ReactDOM.render(
  <**ApolloProvider client={**GraphQLClient**}**>
    <**App **/>
  </**ApolloProvider**>,
  ***document***.getElementById('root'));
registerServiceWorker();

Now when you start your frontend and backend applications you should be able to see Websocket connection from browser development tools. You can watch what kind of data transfer is going on using Networking tab (but I’m sure you already know that!).

Last thing that we need to do is make our Hello world! message available for our users (again, nothing fancy). Let’s connect react-apollo to our main App component. Here is how App.js looks like for this case.

**import **React, { *Component *} **from **'react';
**import **logo **from **'./logo.svg';
**import **'./App.css';
**import **{ *graphql *} **from **'react-apollo';

**const **HelloQuery = *gql*`
  query Hello {
    hello
  }
`;

@graphql(HelloQuery, { name: 'helloQuery' })
**class App extends ***Component *{
  render() {
    **const **{ helloQuery } = **this**.props;

    **return **(
      <**div **className="App">
        <**header **className="App-header">
          <**img **src={logo} className="App-logo" alt="logo" />
          <**h1 **className="App-title">Welcome to React</**h1**>
        </**header**>
        <**p **className="App-intro">
          Message from GraphQL Websocket backend 
          <**string**>{ helloQuery.hello }</**string**>
        </**p**>
      </**div**>
    );
  }
}

**export default **App;

Apollo client will query hello field that we defined as a Root query field, and resolve function will return our text. The main beauty of this process is that after configuring websocket client for Apollo client, the rest of the codebase stays the same, but the performance of data transfer is match better!

This setup is not ideal for most of the applications like where you don’t need always available server, or you want to go with available free services without ability to deploy custom Node.js server, but if you are building some in-house application and want to get max performance, better UI responsiveness, better UX for backend communications and better analytic event messages, you should at least check this out!

We’ve done all TreeScale client’s dashboards using this principle and results are remarkably better than standard REST API with request-response principle. **BUT **you should consider that scalability of real-time connections requires more skills, so be prepared for that, and hack around 💥

👏 So, clap for this! And write your story with this as a comment!

Get the best technology updates and coding tips

Subscribe to our newsletter and stay updated.