Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

grafserv

graphile19.1kMIT0.1.1-beta.27TypeScript support: included

A highly optimized server for GraphQL, powered by Grafast

server, grafast, graphql, graphile, fast, graphite

readme

🔮 Graphile's Crystal Monorepo

GitHub Sponsors Patreon sponsor button Discord chat room Follow

At Graphile we love GraphQL so much we named ourself for our love of it! This repository houses many of the Graphile packages that relate to GraphQL (or relate to the packages that relate to GraphQL, or relate to those package...); the two headline projects are Grafast and PostGraphile but there's many other packages, a fair few of which can be used independently - see below for more details.

Grafast: A cutting-edge planning and execution engine for GraphQL.js ─ use this as a drop-in replacement for the execute method from GraphQL.js and by moving from traditional resolvers to Grafast "plan resolvers" you'll be able to leverage the declarative nature of GraphQL requests to execute your business logic in the most efficient way, leading to reduced server load and happier customers. Use this if you're building your own GraphQL schemas and want the best performance and efficiency without having to put much extra effort in.

PostGraphile: An incredibly low-effort way to build a well structured and high-performance GraphQL API backed primarily by a PostgreSQL database. Our main focusses are performance, automatic best-practices and customisability/extensibility. Use this if you have a PostgreSQL database and you want to use it as the "source of truth" for an auto-generated GraphQL API (which you can still make significant changes to). NOTE: thanks to graphile-export you can also use this as a starting point for an API that you then manage yourself.

➡️ For PostGraphile V4 see the legacy branch

Project summaries

Here's a rough breakdown of the main packages:

  • grafast - standalone cutting-edge planning and execution engine for GraphQL; see above for full description.
  • graphile-export - a package that can (under the right circumstances) export an in-memory dynamically-constructed GraphQL schema to raw JavaScript source code that can be imported and executed
  • jest-serializer-graphql-schema - a simple Jest serializer that understands GraphQL schemas and thus does not fill snapshots with \"\"\" etc.
  • graphile-config - a module that handles the plugins, presets and configuration files for Graphile software - a universal configuration layer.
  • graphile-build - a system for building a GraphQL.js schema from "plugins", particularly useful for auto-generated GraphQL APIs (e.g. PostGraphile uses this) but also useful for hand-rolled schemas that have a lot of modular but widely-used concerns such as connections, naming, etc.
    • graphile-build-pg - plugins for graphile-build that understand @dataplan/pg (i.e. PostgreSQL) services and can generate types, relations, mutations, etc for these database resources.
  • @graphile/lru - an obsessively performant least-recently-used cache (possibly the fastest general purpose LRU cache in Node.js) with a ridiculously tiny feature set; you almost certainly want @isaacs' lru-cache instead of this.
  • pg-sql2 - a library for building highly dynamic SQL-injection-proof PostgreSQL queries using tagged template literals.
  • pg-introspection - a strongly typed introspection library for PostgreSQL, generated from the PostgreSQL documentation to provide up-to-date details of each introspection field.
  • postgraphile - pulls most of the above technologies together; see above for full description.

Crowd-funded open-source software

To help us develop this software sustainably, 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 🤩:

The Guild
The Guild
*
Steelhead
Steelhead
*

* Sponsors the entire Graphile suite

Why the "crystal" monorepo?

Originally what is now Grafast (and was previously DataPlanner) was known by the codename "Graphile Crystal." This lead us to use the 🔮 emoji to represent the project in secret before we announced it publicly, as a codeword for those in the know. Now that Grafast is the name for our planning and execution engine and we needed a name for the monorepo that wasn't too GraphQL specific (since there are things in here that aren't strictly related to GraphQL) and we figured that calling it the Crystal monorepo would honour our original nickname for the project. Rumours that the name was inspired by the maintainers' crystal wedding anniversary are greatly exaggerated.

changelog

grafserv

0.1.1-beta.27

Patch Changes

  • #2578 1d76d2f Thanks @benjie! - 🚨 Ruru has been "rebuilt"! The loading methods and APIs have changed!

    Ruru is now built on top of GraphiQL v5, which moves to using the Monaco editor (the same editor used in VSCode) enabling more familiar keybindings and more features (e.g. press F1 in the editor to see the command palette, and you can now add comments in the variables JSON). This has required a rearchitecture to Ruru's previously "single file" approach since Monaco uses workers which require additional files.

    In this release we have embraced the bundle splitting approach. We now bundle both prettier and mermaid, and they are now loaded on-demand.

    Usage instructions for all environments have had to change since we can no longer serve Ruru as a single HTML file. We now include helpers for serving Ruru's static files from whatever JS-based webserver you are using.

    We've also added some additional improvements:

    • Formatting with prettier now maintains the cursor position (Ctrl-Shift-P/Meta-Shift-P/Cmd-Shift-P depending on platform)
    • All editors are now formatted, not just the GraphQL editor
    • Prettier and mermaid should now work offline
    • Even more GraphiQL props are now passed through, including inputValueDeprecation and schemaDeprecation which you can set to false if your GraphQL server is, ahem, a little behind the GraphQL spec draft.

    🚨 Changes you need to make: 🚨

    • If you are using Ruru directly (i.e. importing from ruru/server), please see the new Ruru README for setup instructions, you'll want to switch out your previous setup. In particular, ruru/bundle no longer exists and you now need to serve the static files (via ruru/static).
    • defaultHTMLParts is no more; instead config.htmlParts (also preset.ruru.htmlParts for Graphile Config users) now allows the entries to be callback functions reducing boilerplate:
      -import { defaultHTMLParts } from "ruru/server";
       const config = {
         htmlParts: {
      -    metaTags: defaultHTMLParts.metaTags + "<!-- local override -->",
      +    metaTags: (base) => base + "<!-- local override -->",
         }
       }
      (alternatively you can use makeHTMLParts(config))
    • Grafserv users: plugin.grafserv.middleware.ruruHTMLParts is renamed to ruruHTML and wraps the generation of the HTML - simply trim Parts from the name and be sure calling next() is the final line of the function
       const plugin = {
         grafserv: {
           middleware: {
      -      ruruHTMLParts(next, event) {
      +      ruruHTML(next, event) {
               const { htmlParts, request } = event;
               htmlParts.titleTag = `<title>${escapeHTML(
                 "Ruru | " + request.getHeader("host"),
               )}</title>`;
               return next();
             },
           },
         },
       };

    Additional changes:

    • RuruConfig.clientConfig has been added for props to explicitly pass to Ruru making it explicit that these will be sent to the client
    • RuruServerConfig has deprecated the client options editorTheme, debugTools and eventSourceInit at the top level; instead these should be passed via RuruServerConfig.clientConfig making it explicit these will be sent to the client and expanding to cover more props
       const config = {
         endpoint: "/graphql",
      +  clientConfig: {
         editorTheme: "dark",
      +  },
       }
  • #2622 a480f6d Thanks @benjie! - 🚨 Since Ruru now needs to serve static assets due to the upgrade to GraphiQL v5 and Monaco, we've had to extend Grafserv to do so. We've (theoretically) added support in the H3, Hono and Fastify adaptors, along with the base node adaptor (used by Node, Express, Koa); however - if you have your own adaptor for a different server, you'll need to be sure to call the .graphiqlStaticHandler for URLs that start with dynamicOptions.graphiqlStaticPath.

    Whilst at it, we've added more places where headers can be added, and we've added a new "raw" ResultType which can be used to serve a Node Buffer with entirely custom headers (e.g. set your own Content-Type).

  • #2600 ad588ec Thanks @benjie! - Mark all peerDependencies=dependencies modules as optional peerDependencies to make pnpm marginally happier hopefully.

  • Updated dependencies [1d76d2f, c54c6db, 24d379a, ad588ec]:

0.1.1-beta.26

Patch Changes

0.1.1-beta.25

Patch Changes

0.1.1-beta.24

Patch Changes

0.1.1-beta.23

Patch Changes

0.1.1-beta.22

Patch Changes

0.1.1-beta.21

Patch Changes

0.1.1-beta.20

Patch Changes

0.1.1-beta.19

Patch Changes

0.1.1-beta.18

Patch Changes

0.1.1-beta.17

Patch Changes

0.1.1-beta.16

Patch Changes

0.1.1-beta.15

Patch Changes

0.1.1-beta.14

Patch Changes

0.1.1-beta.13

Patch Changes

  • #2071 582bd768f Thanks @benjie! - GrafastExecutionArgs now accepts resolvedPreset and requestContext directly; passing these through additional arguments is now deprecated and support will be removed in a future revision. This affects:

    • grafast()
    • execute()
    • subscribe()
    • hookArgs()

    graphile-config has gained a middleware system which is more powerful than it's AsyncHooks system. Old hooks can be emulated through the middleware system safely since middleware is a superset of hooks' capabilities. applyHooks has been renamed to orderedApply (because it applies to more than just hooks), calling applyHooks will still work but is deprecated.

    🚨 grafast no longer automatically reads your graphile.config.ts or similar; you must do that yourself and pass the resolvedPreset to grafast via the args. This is to aid in bundling of grafast since it should not need to read from filesystem or dynamically load modules.

    grafast no longer outputs performance warning when you set GRAPHILE_ENV=development.

    🚨 plugin.grafast.hooks.args is now plugin.grafast.middleware.prepareArgs, and the signature has changed - you must be sure to call the next() function and ctx/resolvedPreset can be extracted directly from args:

     const plugin = {
       grafast: {
    -    hooks: {
    +    middleware: {
    -      args({ args, ctx, resolvedPreset }) {
    +      prepareArgs(next, { args }) {
    +        const { requestContext: ctx, resolvedPreset } = args;
             // ...
    +        return next();
           }
         }
       }
     }

    Many more middleware have been added; use TypeScript's autocomplete to see what's available until we have proper documentation for them.

    plugin.grafserv.hooks.* are still supported but deprecated; instead use middleware plugin.grafserv.middleware.* (note that call signatures have changed slightly, similar to the diff above):

    • hooks.init -> middleware.setPreset
    • hooks.processGraphQLRequestBody -> middleware.processGraphQLRequestBody
    • hooks.ruruHTMLParts -> middleware.ruruHTMLParts

    A few TypeScript types related to Hooks have been renamed, but their old names are still available, just deprecated. They will be removed in a future update:

    • HookObject -> FunctionalityObject
    • PluginHook -> CallbackOrDescriptor
    • PluginHookObject -> CallbackDescriptor
    • PluginHookCallback -> UnwrapCallback
  • Updated dependencies [582bd768f]:

0.1.1-beta.12

Patch Changes

0.1.1-beta.11

Patch Changes

0.1.1-beta.10

Patch Changes

0.1.1-beta.9

Patch Changes

0.1.1-beta.8

Patch Changes

0.1.1-beta.7

Patch Changes

0.1.1-beta.6

Patch Changes

0.1.1-beta.5

Patch Changes

0.1.1-beta.4

Patch Changes

0.1.1-beta.3

Patch Changes

0.1.1-beta.2

Patch Changes

0.1.1-beta.1

Patch Changes

0.1.1-beta.0

Patch Changes

0.0.1-beta.9

Patch Changes

0.0.1-beta.8

Patch Changes

0.0.1-beta.7

Patch Changes

0.0.1-beta.6

Patch Changes

0.0.1-beta.5

Patch Changes

0.0.1-beta.4

Patch Changes

0.0.1-beta.3

Patch Changes

0.0.1-beta.2

Patch Changes

0.0.1-beta.1

Patch Changes

0.0.1-alpha.16

Patch Changes

0.0.1-alpha.15

Patch Changes

0.0.1-alpha.14

Patch Changes

0.0.1-alpha.13

Patch Changes

0.0.1-alpha.12

Patch Changes

0.0.1-alpha.11

Patch Changes

0.0.1-alpha.10

Patch Changes

0.0.1-alpha.9

Patch Changes

0.0.1-alpha.8

Patch Changes

0.0.1-alpha.7

Patch Changes

0.0.1-alpha.6

Patch Changes

0.0.1-alpha.5

Patch Changes

0.0.1-alpha.4

Patch Changes

0.0.1-alpha.3

Patch Changes

0.0.1-alpha.2

Patch Changes

  • #305 3cf35fdb4 Thanks @benjie! - 🚨 Ruru is now a CommonJS module, no longer an ESM module.

    Ruru CLI now reads options from a graphile.config.ts file if present.

    It's now possible to customize the HTML that Ruru is served with (specifically the meta, title, stylesheets, header JS, body content, body JS, and init script), either via configuration:

    import { defaultHTMLParts } from "ruru/server";
    
    const preset: GraphileConfig.Preset = {
      //...
      ruru: {
        htmlParts: {
          titleTag: "<title>GraphiQL with Grafast support - Ruru!</title>",
          metaTags:
            defaultHTMLParts.metaTags +
            `<meta name="viewport" content="width=device-width, initial-scale=1" />`,
        },
      },
    };

    or via a plugin, which allows you to change it on a per-request (per-user) basis:

    const RuruMetaPlugin: GraphileConfig.Plugin = {
      name: "RuruMetaPlugin",
      version: "0.0.0",
      grafserv: {
        hooks: {
          ruruHTMLParts(_info, parts, extra) {
            // extra.request gives you access to request details, so you can customize `parts` for the user
    
            parts.metaTags += `<meta name="viewport" content="width=device-width, initial-scale=1" />`;
          },
        },
      },
    };
  • #307 7c45eaf4e Thanks @benjie! - 🚨 'application/x-www-form-urlencoded' is now opt-in (unless you're using the V4 preset).

    CSRF and CORS are tricky topics. When you use PostGraphile as part of a larger system, it's your responsibility to ensure that you don't open yourself up to CSRF/etc issues (e.g. by using CSRF/XSRF tokens, by using SameSite cookie policies, by checking the Origin of requests, or by using a combination of these or other techniques).

    Out of the box, PostGraphile does not use cookies, so any cross-origin requests are harmless because an attacker without the actual user token in hand can only execute unauthenticated requests.

    However, once cookies (and sessions) enter the equation, suddenly CSRF becomes a risk. Normally you cannot submit an Content-Type: application/json request cross origins (unless you've enabled CORS), so this content type doesn't open CSRF issues on its own, but Content-Type: application/x-www-form-urlencoded can be submitted cross origins without CORS policies. The attacker won't be able to view the response, but that doesn't mean they can't cause havoc by triggering dangerous mutations using the user's credentials.

    We've decided to take the stance of making application/x-www-form-urlencoded opt-in; you can opt-in via your graphile.config.ts (or equivalent) like so:

    import { DEFAULT_ALLOWED_REQUEST_CONTENT_TYPES } from "grafserv";
    
    const preset: GraphileConfig.Preset = {
      //...
    
      grafserv: {
        //...
    
        allowedRequestContentTypes: [
          ...DEFAULT_ALLOWED_REQUEST_CONTENT_TYPES,
          "application/x-www-form-urlencoded",
        ],
      },
    };

    If you're using the V4 preset then we pull in the V4 behavior of enabling this content type by default (since you presumably already have protections in place); however we recommend disabling this media type if you're not using it:

    import { DEFAULT_ALLOWED_REQUEST_CONTENT_TYPES } from "grafserv";
    
    const preset: GraphileConfig.Preset = {
      //... extends V4 preset ...
    
      grafserv: {
        //...
    
        allowedRequestContentTypes: DEFAULT_ALLOWED_REQUEST_CONTENT_TYPES,
      },
    };

    Note that this media type is not currently part of the GraphQL-over-HTTP specification so disabling it does not make your server non-compliant.

  • Updated dependencies [3cf35fdb4, 3df3f1726]:

0.0.1-alpha.1

Patch Changes

0.0.1-1.3

Patch Changes

0.0.1-1.2

Patch Changes

0.0.1-1.1

Patch Changes

0.0.1-0.25

Patch Changes

0.0.1-0.24

Patch Changes

0.0.1-0.23

Patch Changes

0.0.1-0.22

Patch Changes

0.0.1-0.21

Patch Changes

0.0.1-0.20

Patch Changes

0.0.1-0.19

Patch Changes

0.0.1-0.18

Patch Changes

0.0.1-0.17

Patch Changes

0.0.1-0.16

Patch Changes

0.0.1-0.15

Patch Changes

0.0.1-0.14

Patch Changes

0.0.1-0.13

Patch Changes

0.0.1-0.12

Patch Changes

0.0.1-0.11

Patch Changes

0.0.1-0.10

Patch Changes

0.0.1-0.9

Patch Changes

0.0.1-0.8

Patch Changes

  • c4213e91d - Add pgl.getResolvedPreset() API; fix Ruru respecting graphqlPath setting; replace 'instance' with 'pgl'/'serv' as appropriate; forbid subscriptions on GET

0.0.1-0.7

Patch Changes

0.0.1-0.6

Patch Changes

0.0.1-0.5

Patch Changes

0.0.1-0.4

Patch Changes

0.0.1-0.3

Patch Changes

0.0.1-0.2

Patch Changes

0.0.1-0.1

Patch Changes

0.0.1-0.0

Patch Changes