The Guild LogoThe Guild Monogram

Search docs

Search icon

Products by The Guild

Products

Hive logoHive blurred logo

Hive

Schema Registry for your GraphQL Workflows

Envelop Logo

Envelop

Get Started

Plugins Lifecycle#

Plugins Lifecycle#

Plugins are executed in order of their usage, and inject functionality serially, so aim to keep your plugins simple and standalone as much as possible.

The before functions are called in order, and then the after function of each hook will be called in the same order, when the phase has done.

The basic API allow you to keep the JS closure between before and after, for example:

const myPlugin = { onParse({ params }) { // This is the before function return ({ result }) => { // The is the after function, // JS Closure allow me to access the params here as well }; }, };

All plugins lifecycle methods are executed in LIFO order (Last-in, First-out) to make timing more consistent.

The improved context#

While in regular GraphQL executions, the context is built right before execute happens, in envelop we allow plugin developers to take part it that context from all phases.

While calling getEnveloped function (the result of envelop({ plugins: [ ... ]})), you can pass any custom object that will be the base for your GraphQL execution context.

In most cases, you'll pass the incoming HTTP request (or, just the relevant parts of it) to make it available for the plugins you use:

import { envelop } from '@envelop/core'; const getEnveloped = envelop({ plugins: [ /* ... plugins ... */ ], }); myHttpServer.on('request', async req => { const { parse, validate, contextFactory, execute, schema } = getEnveloped({ req }); // ... });

Plugins might also use this context to keep a contextual reference for objects they might need across stages.

So for example, if you wish to make some data from parse stage available for you in execute phase, you can extend the context while running onParse and then access that data in onExecute:

const myPlugin = { onParse({ extendContext }) => { extendContext({ myVar: 'test' }); }, onExecute({ args }) => { const myVar = args.contextValue.myVar; }, };

Plugins API#

You can find the complete signature for plugins API here.

onPluginInit(api)#

This method is called only once when the plugin is being initialized. This hook is triggered only once, and is useful for setting up the plugin.

API:

  • setSchema - sets the initial schema to be used.
  • plugins - list of all other loaded plugins.
  • addPlugin - adds a plugin to the list of plugins.

onEnveloped(api)#

This method is called every time getEnveloped is called, and per request. This is useful if you need to do some setup right before an incoming execution flow.

API:

  • setSchema - sets the initial schema to be used.
  • context - the initial context object passed to getEnveloped, including the context built by plugins that ran before.
  • extendContext - extends the initial context object with additional fields.

onParse(api)#

Called every time an operation is being executed.

before API:

  • params - the original parameters passes to parse function.
  • parseFn - the current parse function. By default, it's the one from graphql package.
  • setParseFn - Replaces the parse function with a custom function.
  • setParsedDocument - sets the parse result. Setting this will skip calling parse for the executed operation.
  • context - the context object built so far by other plugins.
  • extendContext - extends the context object with additional fields.

after API:

  • result - the result DocumentNode of the parsing function.
  • replaceParseResult - replaces the parsed result.
  • context - the context object built so far by other plugins.
  • extendContext - extends the context object with additional fields.

onValidate(api)#

Called every time an operation is being executed.

before API:

  • params - the original parameters passes to validate function.
  • validateFn - the current validate function. By default, it's the one from graphql package.
  • setValidationFn - Replaces the validate function with a custom function.
  • addValidationRule - Adds a validation rule to the list of default validation rules (as defined in graphql package).
  • setResult - sets the validation result. Setting this will skip calling validate for the executed operation.
  • context - the context object built so far by other plugins.
  • extendContext - extends the context object with additional fields.

after API:

  • valid - A boolean indicates if the validation passed.
  • result - null in case of valid document, otherwise an array of validation errors.
  • context - the context object built so far by other plugins.
  • extendContext - extends the context object with additional fields.

onContext(api)#

Called every time an operation is being executed. Used for building the GraphQL context incrementally.

before API:

  • context - the context object built so far by other plugins.
  • extendContext - extends the context object with additional fields.

after API:

  • context - the eventual built context, by all plugins.
  • extendContext - extends the context object with additional fields.

onExecute(api)#

Called every time an operation is being executed. The return value of this function is extended, and allow you to hooks into resolver calls if needed.

before API:

  • args - arguments passes to execute (contains the document, variables and everything else that needed for executing the GraphQL operation)
  • executeFn - the execute function to use, by default it's the one from graphql package.
  • setExecuteFn - replaces the execute function.
  • setResultAndStopExecution - sets the result of the execution immediately. Calling this function will stop execution.
  • extendContext - allow you to extend the context before executing the operation.

You can return an object from that function, with the following fields:

onExecuteDone API:

Triggered when the execution of the operation is done.

  • result - the execution result, or AsyncIterable in case of stream response.
  • setResult - replaces the result. can either be with data or errors.

Since envelop aims to support stream responses (for live queries, or @stream/@defer), the result might be an AsyncIterable of multiple execution results.

If you wish you plugin to support this, please make sure to use the handleStreamOrSingleExecutionResult helper, like that:

import { Plugin, handleStreamOrSingleExecutionResult } from '@envelop/types'; const myPlugin = (): Plugin => { return { onExecute({ args }) { return { onExecuteDone: payload => { return handleStreamOrSingleExecutionResult(payload, ({ result, setResult }) => { // Here you can access result, and modify it with setResult if needed }); }, }; }, }; };

Alternately, if you don't need to support stream responses, you can use the isAsyncIterable function as type-guard:

import { Plugin, isAsyncIterable } from '@envelop/types'; const myPlugin = (): Plugin => { return { onExecute({ args }) { return { onExecuteDone: ({ result, setResult }) => { if (isAsyncIterable(result)) { // Here you can access result, and modify it with setResult if needed } }, }; }, }; };

onResolverCalled API:

Triggered when a resolver is called during the execution of the operation.

  • params - an object with { root, args, context, info } that was originally passed to the resolver.

You can also return a function to run after the resolver is done, with the following API:

  • result - the resolver return value.
  • setResult - replaces the resolver return value.

onSubscribe(api)#

Called every time a subscription operation is being executed. The return value of this function is extended, and allow you to hooks into resolver calls if needed.

before API:

  • args - arguments passes to subscribe (contains the document, variables and everything else that needed for executing the GraphQL operation)
  • subscribeFn - the subscribe function to use, by default it's the one from graphql package.
  • setSubscribeFn - replaces the subscribe function.
  • extendContext - allow you to extend the context before executing the operation.

You can return an object from that function, with the following fields:

onSubscribeResult API:

Triggered when subscription result is being emitted from a subscription execution.

  • result - the subscription result.
  • setResult - replaces the result. can either be with data or errors.

onResolverCalled API:

Triggered when a resolver is called during the execution of the operation.

  • params - an object with { root, args, context, info } that was originally passed to the resolver.

You can also return a function to run after the resolver is done, with the following API:

  • result - the resolver return value.
  • setResult - replaces the resolver return value.

onSchemaChange(api)#

envelop allow you to manage a reference to a schema, that you can later access and use within your server.

Some plugins (like gateway implementations) could potentially change the schema while running, so envelop will trigger that event in case of a schema change after all plugins have initialized.

API:

  • schema - the GraphQLSchema
  • replaceSchema - replaces the schema. Calling this will trigger onSchemaChange for all other plugins (except for the one that initiated the change);