GraphQL Helix HTTP Server Utilities

1.13.0 · active · verified Sun Apr 19

GraphQL Helix is a collection of framework and runtime agnostic utility functions designed for building GraphQL HTTP servers. It focuses on adherence to the GraphQL over HTTP specification, enabling a single HTTP endpoint for queries, mutations, subscriptions, and features like `@defer` and `@stream` directives. The package supports both server push and client pull paradigms for real-time data. It is known for its minimal footprint, having zero dependencies outside of `graphql-js` itself, and works across Node.js, Deno, and browser environments. The current stable version is 1.13.0, with minor and patch releases occurring frequently, as indicated by recent changes adding `extensions` and `operationName` to `ExecutionContext` and improving `accept` header handling. Its key differentiators include its agnosticism to specific HTTP frameworks and runtimes, strong HTTP-first and spec-compliant approach, and a focus on providing core abstractions without bloat or integrated platforms.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates setting up a basic GraphQL HTTP server using `graphql-helix` with Express, including support for queries, mutations (implied by `processRequest`), GraphiQL, and subscriptions via SSE.

import express from 'express';
import { buildSchema } from 'graphql';
import {
  getGraphQLParameters,
  processRequest,
  renderGraphiQL,
  shouldRenderGraphiQL,
} from 'graphql-helix';

const schema = buildSchema(`
  type Query {
    hello: String
  }
  type Subscription {
    greeting: String
  }
`);

const rootValue = {
  hello: () => 'Hello GraphQL Helix!',
  greeting: async function* () {
    for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao']) {
      yield { greeting: hi };
      await new Promise(resolve => setTimeout(resolve, 500));
    }
  },
};

const app = express();
app.use(express.json());

app.use('/graphql', async (req, res) => {
  const request = {
    body: req.body,
    headers: req.headers,
    method: req.method,
    query: req.query,
  };

  if (shouldRenderGraphiQL(request)) {
    res.send(renderGraphiQL());
  } else {
    const { operationName, query, variables } = getGraphQLParameters(request);

    const result = await processRequest({
      operationName,
      query,
      variables,
      request,
      schema,
      contextFactory: () => ({ request }),
      rootValue,
    });

    if (result.type === 'RESPONSE') {
      result.headers.forEach(({ name, value }) => res.setHeader(name, value));
      res.status(result.status);
      res.json(result.payload);
    } else if (result.type === 'MULTIPART_RESPONSE') {
      res.writeHead(200, {
        Connection: 'keep-alive',
        'Content-Type': 'multipart/mixed; boundary="-"',
        'Transfer-Encoding': 'chunked',
      });

      req.on('close', () => {
        result.unsubscribe();
      });

      res.write('---');

      for await (const chunk of result.subscribe()) {
        res.write(`\r\n${JSON.stringify(chunk)}\r\n---`);
      }
      res.end();
    } else if (result.type === 'PUSH') {
      res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        Connection: 'keep-alive',
        'Cache-Control': 'no-cache',
      });

      req.on('close', () => {
        result.unsubscribe();
      });

      for await (const event of result.subscribe()) {
        res.write(`data: ${JSON.stringify(event)}\n\n`);
      }
    }
  }
});

app.listen(4000, () => console.log('GraphQL server running on http://localhost:4000/graphql'));

view raw JSON →