v2
@envelop/core

@envelop/core

This is the core package for envelop, it comes with the execution pipeline wrapper and some basic core plugins you can use for creating your initial Envelop instance.

Built-In Plugins

useSchema

This plugin is the simplest plugin for specifying your GraphQL schema. You can specify a schema created from any tool that emits GraphQLSchema object.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine, useSchema } from '@envelop/core'
 
const mySchema = buildSchema(/* ... */)
 
const getEnveloped = envelop({
  plugins: [
    useSchema(mySchema)
    // ... other plugins
  ]
})

useAsyncSchema

This plugin is the simplest plugin for specifying your GraphQL schema but in an async way.

If you are using a framework that creates the schema in an async way, you can either use this plugin, or await for the schema and then use useSchema.

import { buildSchema } from 'graphql'
import { envelop, useAsyncSchema } from '@envelop/core'
 
const getSchema = async (): Promise<GraphQLSchema> => {
  // return schema when it's ready
}
 
const getEnveloped = envelop({
  plugins: [
    useAsyncSchema(getSchema())
    // ... other plugins
  ]
})

useErrorHandler

This plugin invokes a custom function every time execution encounters an error.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine, useErrorHandler } from '@envelop/core'
 
const getEnveloped = envelop({
  plugins: [
    useErrorHandler(error => {
      // This callback is called per each GraphQLError emitted during the execution phase
    })
    // ... other plugins
  ]
})
💡

Note: The handler is invoked for each error. So an execution result with multiple errors will yield multiple calls.

useExtendContext

Easily extends the context with custom fields.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine, useExtendContext } from '@envelop/core'
 
const getEnveloped = envelop({
  plugins: [
    useExtendContext(async contextSoFar => {
      return {
        myCustomField: {
          /* ... */
        }
      }
    })
    // ... other plugins
  ]
})

useLogger

Logs parameters and information about the execution phases. You can easily plug in your custom logger.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine, useLogger } from '@envelop/core'
 
const getEnveloped = envelop({
  plugins: [
    useLogger({
      logFn(eventName, args) {
        // Event could be `execute-start` / `execute-end` / `subscribe-start` / `subscribe-end`
        // `args` will include the arguments passed to execute/subscribe (in case of "start" event) and additional result in case of "end" event.
      }
    })
    // ... other plugins
  ]
})

usePayloadFormatter

Allow you to format/modify the execution result payload before returning it to your consumer.

The second argument executionArgs provides additional information for your formatter. It consists of contextValue, variableValues, document, operationName, and other properties.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine, usePayloadFormatter } from '@envelop/core'
 
const getEnveloped = envelop({
  plugins: [
    usePayloadFormatter((result, executionArgs) => {
      // Return a modified result here,
      // Or `false`y value to keep it as-is.
    })
    // ... other plugins
  ]
})

useTiming

It’s a simple time metric collection for every phase in your execution. You can easily customize the behavior of each timing measurement. By default, the timing is printed to the log, using console.log.

import * as GraphQLJS from 'graphql'
import { envelop, useEngine } from '@envelop/core'
 
const getEnveloped = envelop({
  plugins: [
    useTiming({
      // All options are optional. By default it just print it to the log.
      // ResultTiming is an object built with { ms, ns } (milliseconds and nanoseconds)
      onContextBuildingMeasurement: (timing: ResultTiming) => {},
      onExecutionMeasurement: (args: ExecutionArgs, timing: ResultTiming) => {},
      onSubscriptionMeasurement: (args: SubscriptionArgs, timing: ResultTiming) => {},
      onParsingMeasurement: (source: Source | string, timing: ResultTiming) => {},
      onValidationMeasurement: (document: DocumentNode, timing: ResultTiming) => {},
      onResolverMeasurement: (info: GraphQLResolveInfo, timing: ResultTiming) => {}
    })
    // ... other plugins
  ]
})

useMaskedErrors

Prevent unexpected error messages from leaking to the GraphQL API consumers.

import { makeExecutableSchema } from 'graphql'
import { envelop, EnvelopError, useMaskedErrors, useSchema } from '@envelop/core'
 
const schema = makeExecutableSchema({
  typeDefs: /* GraphQL */ `
    type Query {
      something: String!
      somethingElse: String!
      somethingSpecial: String!
    }
  `,
  resolvers: {
    Query: {
      something() {
        throw new EnvelopError('Error that is propagated to the clients.')
      },
      somethingElse() {
        throw new Error("Unsafe error that will be masked as 'Unexpected Error.'.")
      },
      somethingSpecial() {
        throw new EnvelopError('The error will have an extensions field.', {
          code: 'ERR_CODE',
          randomNumber: 123
        })
      }
    }
  }
})
 
const getEnveloped = envelop({
  plugins: [useSchema(schema), useMaskedErrors()]
})

Utilities

enableIf

This utility is helpful when you want to enable a plugin only when a certain condition is met.

import { enableIf, envelop, useMaskedErrors } from '@envelop/core'
 
const isProd = process.env.NODE_ENV === 'production'
 
const getEnveloped = envelop({
  plugins: [
    // This plugin is enabled only in production
    enableIf(isProd, useMaskedErrors()),
    // you can also pass function
    enableIf(isProd, () => useMaskedErrors())
    // ... other plugins
  ]
})