Get Started

Get Started

Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket spec (opens in a new tab) compliant server and client.

For detailed documentation and API reference, check out the documentation page. If you need short and concise code snippets for starting with common use-cases, the recipes page is the right place for you.

Install

Terminal
yarn add graphql-ws

Create a GraphQL schema

import { GraphQLSchema, GraphQLObjectType, GraphQLString } from 'graphql';
 
/**
 * Construct a GraphQL schema and define the necessary resolvers.
 *
 * type Query {
 *   hello: String
 * }
 * type Subscription {
 *   greetings: String
 * }
 */
export const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: {
      hello: {
        type: GraphQLString,
        resolve: () => 'world',
      },
    },
  }),
  subscription: new GraphQLObjectType({
    name: 'Subscription',
    fields: {
      greetings: {
        type: GraphQLString,
        subscribe: async function* () {
          for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
            yield { greetings: hi };
          }
        },
      },
    },
  }),
});

Start the server

With ws (opens in a new tab)

import { WebSocketServer } from 'ws'; // yarn add ws
// import ws from 'ws'; yarn add ws@7
// const WebSocketServer = ws.Server;
import { useServer } from 'graphql-ws/lib/use/ws';
import { schema } from './previous-step';
 
const server = new WebSocketServer({
  port: 4000,
  path: '/graphql',
});
 
useServer({ schema }, server);
 
console.log('Listening to port 4000');

With uWebSockets.js (opens in a new tab)

import uWS from 'uWebSockets.js'; // yarn add uWebSockets.js@uNetworking/uWebSockets.js#<tag>
import { makeBehavior } from 'graphql-ws/lib/use/uWebSockets';
import { schema } from './previous-step';
 
uWS
  .App()
  .ws('/graphql', makeBehavior({ schema }))
  .listen(4000, (listenSocket) => {
    if (listenSocket) {
      console.log('Listening to port 4000');
    }
  });

With @fastify/websocket (opens in a new tab)

import Fastify from 'fastify'; // yarn add fastify
import fastifyWebsocket from '@fastify/websocket'; // yarn add @fastify/websocket
import { makeHandler } from 'graphql-ws/lib/use/@fastify/websocket';
import { schema } from './previous-step';
 
const fastify = Fastify();
fastify.register(fastifyWebsocket);
 
fastify.register(async (fastify) => {
  fastify.get('/graphql', { websocket: true }, makeHandler({ schema }));
});
 
fastify.listen(4000, (err) => {
  if (err) {
    fastify.log.error(err);
    return process.exit(1);
  }
  console.log('Listening to port 4000');
});

With Bun (opens in a new tab)

import { makeHandler, handleProtocols } from 'graphql-ws/lib/use/lib/bun';
import { schema } from './previous-step';
 
Bun.serve({
  fetch(req, server) {
    const [path, _search] = req.url.split('?');
    if (!path.endsWith('/graphql')) {
      return new Response('Not Found', { status: 404 });
    }
    if (req.headers.get('upgrade') != 'websocket') {
      return new Response('Upgrade Required', { status: 426 });
    }
    if (handleProtocols(req.headers.get('sec-websocket-protocol') || '')) {
      return new Response('Bad Request', { status: 404 });
    }
    if (!server.upgrade(req)) {
      return new Response('Internal Server Error', { status: 500 });
    }
    return new Response();
  },
  websocket: makeHandler({ schema }),
  port: 4000,
});
 
console.log('Listening to port 4000');

With Deno (opens in a new tab)

import { serve } from 'https://deno.land/std/http/mod.ts';
import {
  makeHandler,
  GRAPHQL_TRANSPORT_WS_PROTOCOL,
} from 'https://esm.sh/graphql-ws/lib/use/deno';
import { schema } from './previous-step.ts';
 
const handler = makeHandler({ schema });
 
serve(
  (req: Request) => {
    const [path, _search] = req.url.split('?');
    if (!path.endsWith('/graphql')) {
      return new Response('Not Found', { status: 404 });
    }
    if (req.headers.get('upgrade') != 'websocket') {
      return new Response('Upgrade Required', { status: 426 });
    }
    const { socket, response } = Deno.upgradeWebSocket(req, {
      protocol: GRAPHQL_TRANSPORT_WS_PROTOCOL,
      idleTimeout: 12_000,
    });
    handler(socket);
    return response;
  },
  { port: 4000 },
);

Use the client

import { createClient } from 'graphql-ws';
 
const client = createClient({
  url: 'ws://localhost:4000/graphql',
});
 
// query
(async () => {
  const result = await new Promise((resolve, reject) => {
    let result;
    client.subscribe(
      {
        query: '{ hello }',
      },
      {
        next: (data) => (result = data),
        error: reject,
        complete: () => resolve(result),
      },
    );
  });
 
  expect(result).toEqual({ hello: 'Hello World!' });
})();
 
// subscription
(async () => {
  const onNext = () => {
    /* handle incoming values */
  };
 
  let unsubscribe = () => {
    /* complete the subscription */
  };
 
  await new Promise((resolve, reject) => {
    unsubscribe = client.subscribe(
      {
        query: 'subscription { greetings }',
      },
      {
        next: onNext,
        error: reject,
        complete: resolve,
      },
    );
  });
 
  expect(onNext).toBeCalledTimes(5); // we say "Hi" in 5 languages
})();