JSPM

  • Created
  • Published
  • Downloads 5683
  • Score
    100M100P100Q126056F
  • License MIT

A highly optimized server for GraphQL, powered by Grafast

Package Exports

  • grafserv
  • grafserv/express/v4
  • grafserv/fastify/v4
  • grafserv/koa/v2
  • grafserv/node

Readme

grafserv

Patreon sponsor button Discord chat room Package on npm MIT license Follow

A highly performant GraphQL server for Node.js, powered by Grafast.

Documentation: https://grafast.org/grafserv/

Crowd-funded open-source software

To help us develop this software sustainably under the MIT license, we ask all individuals and businesses that use it to help support its ongoing maintenance and development via sponsorship.

Click here to find out more about sponsors and sponsorship.

And please give some love to our featured sponsors 🤩:

Surge
Surge
*
Netflix
Netflix
*
The Guild
The Guild
*
Qwick
Qwick
*
Chad Furman
Chad Furman
*
Dovetail
Dovetail
*
Enzuzo
Enzuzo
*
Stellate
Stellate
*

* Sponsors the entire Graphile suite

Usage

Grafserv supports many different servers, and because each server is different each has their own entrypoint, e.g. grafserv/node for the Node.js HTTP server or grafserv/express/v4 for Express v4. Generally you import the grafserv function from the relevant entrypoint for your server of choice and then create an instance:

const serv = grafserv({ schema, preset });

grafserv is passed the GraphQL schema to use (if it's available, otherwise passing either null or a promise is also acceptable) and a graphql-config preset - i.e. your configuration.

Calling grafserv will return an instance; this instance will have a number of helpers on it, including helpers specific to integrating it with your framework of choice. For servers that operate on a middleware basis this is typically serv.addTo(app) (which allows registering multiple route handlers), though different servers may have different APIs, such as serv.createGraphQLHandler() for Lambda and Next.js.

Note: There is little value in Grafserv reimplementing every non-GraphQL concern your server may have, so instead it leans on the ecosystem of your chosen server to handle things like compression, rate limits, sessions, cookies, etc. For example, to compress your responses you'd need to use a module like compression for Express, koa-compress for Koa, or @fastify/compress for Fastify.

serv.release()

Releases any resources created by the instance; no further requests should be handled (though currently active requests will be allowed to complete).

// TODO: consider terminating subscriptions or other long-lived things.

serv.onRelease(cb)

Adds cb to the list of callbacks to be called when the server is released; useful for releasing resources you created only for the server. Callbacks will be called in reverse order that they were added.

serv.setSchema(newSchema)

Replaces the schema to use for future requests (currently active requests are unaffected) - this is primarily used for "watch" mode.

serv.setPreset(newPreset)

Replaces the config to use for future requests (currently active requests are unaffected) - this is primarily used for "watch" mode. Note that certain configuration changes might not be reflected by certain servers until a restart.

serv.getSchema()

Returns either the GraphQL schema that is currently in use, or a promise to the same.

serv.getPreset()

Returns the resolved graphile-config preset that is currently in use.

Servers

Node HTTP server

import { createServer } from "node:http";
import { grafserv } from "grafserv/node";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create a Node HTTP server
const server = createServer();
server.on("error", (e) => {
  console.error(e);
});

// Create a Grafserv instance
const serv = grafserv({ schema, preset });

// Mount the request handler into a new HTTP server, and register websockets if
// desired
serv.addTo(server).catch((e) => {
  console.error(e);
  process.exit(1);
});

// Start the Node server
server.listen(preset.grafserv.port ?? 5678);

Express V4

import { createServer } from "node:http";
import express from "express";
import { grafserv } from "grafserv/express/v4";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create an express app
const app = express();
// (Add any Express middleware you want here.)

// Create a Node HTTP server, mounting Express into it
const server = createServer(app);
server.on("error", (e) => {
  console.error(e);
});

// Create a Grafserv instance
const serv = grafserv({ schema, preset });

// Add the Grafserv instance's route handlers to the Express app, and register
// websockets if desired
serv.addTo(app, server).catch((e) => {
  console.error(e);
  process.exit(1);
});

// Start the Express server
server.listen(preset.grafserv.port ?? 5678);

Koa V2

import { createServer } from "node:http";
import Koa from "koa";
import { grafserv } from "grafserv/koa/v2";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create a Koa app
const app = new Koa();
// (Add any Koa middleware you want here.)

// Create a Node HTTP server, mounting Koa into it
const server = createServer(app);
server.on("error", (e) => {
  console.error(e);
});

// Create a Grafserv instance
const serv = grafserv({ schema, preset });

// Add the Grafserv instance's route handlers to the Koa app, and register
// websockets if desired
serv.addTo(app, server).catch((e) => {
  console.error(e);
  process.exit(1);
});

// Start the Koa server
server.listen(preset.grafserv.port ?? 5678);

Fastify V4

import Fastify from "fastify";
// import websocket from '@fastify/websocket'
import { grafserv } from "grafserv/fastify/v4";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create a Fastify app
const app = Fastify({
  logger: true,
});
// (Add any Fastify middleware you want here.)
// await app.register(websocket);

// Create a Grafserv instance
const serv = grafserv({ schema, preset });

// Add the Grafserv instance's route handlers to the Fastify app
serv.addTo(app).catch((e) => {
  console.error(e);
  process.exit(1);
});

// Start the Fastify server
app.listen({ port: preset.grafserv.port ?? 5678 }, (err, address) => {
  if (err) throw err;
  console.log(`Server is now listening on ${address}`);
});

Next.js API route

TODO: actually implement this!

Grafserv handles a number of API routes, so you should define one for each of the things you care about. It's critical that you ensure that the paths line up with those used in the Graphile config, otherwise the assets will not correctly be served/referenced, this may cause issues when communicating between [Ruru][] and GraphQL.

// utils/grafserv.mjs
import { grafserv } from "grafserv/next/v13";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create a shared Grafserv instance
export const serv = grafserv({ schema, preset });
// pages/api/graphql.mjs
import { serv } from "../../utils/grafserv.mjs";

// Create and export the `/graphql` route handler
const handler = serv.createGraphQLHandler();
export default handler;
// pages/api/ruru.mjs
import { serv } from "../../utils/grafserv.mjs";

// Create and export the `/ruru` route handler
const handler = serv.createRuruHandler();
export default handler;

Lambda

TODO: actually implement this!

import { grafserv } from "grafserv/lambda";
import preset from "./graphile.config.mjs";
import schema from "./schema.mjs";

// Create a Grafserv instance
const serv = grafserv({ schema, preset });

// Export a lambda handler for GraphQL
export const handler = serv.createGraphQLHandler();