@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
]
})