Skip to main content

Configuration

Grafast can operate without configuration; however if you'd like to customized advanced settings you may do so by passing a resolved Graphile Config preset to the grafast() function; this is normally handled for you by your Grafast server (e.g. Grafserv or envelop).

Typically you'd also pass a requestContext object that's used to share information about the wider request with the preset (e.g. so it can read HTTP headers).

graphile.config.ts is not automatically read

Grafast does not automatically search for this configuration, you (or your server framework) must pass it explicitly.

Usage

Your configuration preset is typically stored to a graphile.config.ts file (perhaps with an alternative extension), and Grafast configuration options go in the grafast scope:

graphile.config.ts
import type {} from "grafast";

const preset: GraphileConfig.Preset = {
grafast: {
/* options go here */
},
};

export default preset;

You must then import and resolve this preset, passing the result to grafast({...}):

import { resolvePreset } from "graphile-config";
import { grafast } from "grafast";
import preset from "./graphile.config.ts";
import schema from "./schema.ts";

const resolvedPreset = resolvePreset(preset);

const result = await grafast({
resolvedPreset,
requestContext: {
/* Typically populated by your server */
},
schema,
source: /* GraphQL */ `
{
__typename
}
`,
});

Example

Adding request data to GraphQL context

In this configuration, we use the grafast.context callback function to further populate the GraphQL context with information from the HTTP request, if there is one. Assuming we're using grafserv with our Express v4 server, the requestContext.expressv4 object should be populated; GraphQL calls that do not go through this adaptor may not populate this value and thus we use optional chaining for safe access. Finally we extract the user's ID (if there is one) and return it in an object to be merged with the GraphQL context passed into the grafast({...}) call.

const preset: GraphileConfig.Preset = {
grafast: {
context(requestContext, args) {
const req = requestContext.expressv4?.req;
const userId = req?.user?.id;
return { userId };
},
},
};

Reference

Overview

{
context?: Partial<Grafast.Context> | ((ctx: Partial<Grafast.RequestContext>, args: Grafast.ExecutionArgs) => PromiseOrValue<Partial<Grafast.Context>>);
explain?: boolean | string[];
maxPlanningDepth?: number;
timeouts?: GrafastTimeouts;

// Advanced
distributorPauseDuration?: number;
distributorTargetBufferSize?: number;
distributorTargetBufferSizeIncrement?: number;
}

grafast.context

Type: Partial<Grafast.Context> | ((ctx: Partial<Grafast.RequestContext>, args: Grafast.ExecutionArgs) => PromiseOrValue<Partial<Grafast.Context>>) | undefined

An object to merge into the GraphQL context. Alternatively, pass an (optionally asynchronous) function that returns an object to merge into the GraphQL context.

grafast.explain

Type: boolean | string[] | undefined

A list of 'explain' types that should be included in extensions.explain.

  • plan will cause the plan JSON to be included
  • other values are dependent on the plugins in play

If set to true then all possible explain types will be exposed.

grafast.maxPlanningDepth

Type: number | undefined

How many planning layers deep do we allow? Should be handled by validation.

A planning layer can happen due to:

  • A nested selection set
  • Planning a field return type
  • A list position
  • A polymorphic type
  • A deferred/streamed response

These reasons may each cause 1, 2 or 3 planning layers to be added, so this limit should be set quite high - e.g. 6x the selection set depth.

grafast.timeouts

Type: GrafastTimeouts | undefined

Advanced

Only use these settings if you know what you are doing!

grafast.distributorPauseDuration

Advanced

Type: number | undefined

Duration (in milliseconds) for the distributor to pause whilst waiting for the slowest consumer to advance once the distributorTargetBufferSize has been reached.

Must be at least 0.

grafast.distributorTargetBufferSize

Advanced

Type: number | undefined

This supports the $step.cloneStreams = true option, allowing multiple consumers to consume the same underlying stream, but tries to avoid any one consumer getting more than distributorTargetBufferSize items ahead of any other. When a fast consumer gets this far ahead of the slowest consumer, it will be paused for distributorPauseDuration milliseconds to allow the slowest consumer to advance. Should the slowest consumer not advance in time, the fast consumer will be allowed to continue and all intermediary results will be cached - so beware of memory exhaustion and be sure to place sensible limits on your queries (and construct them wisely).

This must be set higher than the largest @stream(initialCount:) argument you want to support.

grafast.distributorTargetBufferSizeIncrement

Advanced

Type: number | undefined

When the distributorTargetBufferSize is exceeded, every time we get distributorTargetBufferSizeIncrement items further ahead, we'll pause again.

Must be at least 1. Recommend you set this fairly large.