Package Exports
- grafserv
- grafserv/express/v4
- grafserv/fastify/v4
- grafserv/koa/v2
- grafserv/node
Readme
grafserv
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 * |
![]() Netflix * |
![]() The Guild * |
![]() Qwick * |
![]() Chad Furman * |
![]() Dovetail * |
![]() Enzuzo * |
![]() 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();