Get Started
Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket spec 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
npm i 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
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
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
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
import { makeHandler, handleProtocols } from 'graphql-ws/lib/use/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
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 query = client.iterate({
query: '{ hello }',
});
const { value } = await query.next();
expect(value).toEqual({ hello: 'world' });
})();
// subscription
(async () => {
const subscription = client.iterate({
query: 'subscription { greetings }',
});
for await (const event of subscription) {
expect(event).toEqual({ greetings: 'Hi' });
// complete a running subscription by breaking the iterator loop
break;
}
})();