Envelop

Envelop is a lightweight library allowing developers to easily develop, sha...

README

Envelop


envelop is a lightweight JavaScript (/TypeScript) library for wrapping GraphQL execution layer and flow, allowing developers to develop, share
and collaborate on GraphQL-related plugins while filling the missing pieces in GraphQL implementations.

envelop aims to extend the GraphQL execution flow by adding plugins that enrichs the feature set of your application.


@envelop/core: npm version

Envelop is created and maintained by The Guild, and used in production by our clients.


### [Envelop Key Concepts](<(https://www.envelop.dev/docs#key-concepts)>)

- Lightweight
- Wraps the entire GraphQL pipeline, based on plugins
- Low-level API for extending the execution layer
- Agnostic to GraphQL Engine
- Agnostic to the HTTP layer
- Agnostic to the schema tools
- Plugins-based usage
- No vendor lock-in
- Amazing TypeScript support



Start by adding the core of Envelop to your codebase:

  1. ```
  2. yarn add graphql @envelop/core
  3. ```

Then, create a simple Envelop based on your GraphQL schema:

  1. ```ts
  2. import * as GraphQLJS from 'graphql'
  3. import { envelop, useEngine, useSchema } from '@envelop/core'

  4. const mySchema = buildSchema(/* ... */) // GraphQLSchema

  5. const getEnveloped = envelop({
  6.   plugins: [useEngine(GraphQLJS), useSchema(mySchema)]
  7. })
  8. ```

The result of envelop is a function that allows you to get everything you need for the GraphQL execution: parse, validate, contextBuilder and execute. Use that to run the client's GraphQL queries. Here's a pseudo-code example of how it should look like:

  1. ```ts
  2. const httpServer = createServer()

  3. httpServer.on('request', async (req, res) => {
  4.   // Here you get the alternative methods that are bundled with your plugins
  5.   // You can also pass the "req" to make it available for your plugins or GraphQL context.
  6.   const { parse, validate, contextFactory, execute, schema } = getEnveloped({ req })

  7.   // Parse the initial request and validate it
  8.   const { query, variables } = JSON.parse(req.payload)
  9.   const document = parse(query)
  10.   const validationErrors = validate(schema, document)

  11.   if (validationErrors.length > 0) {
  12.     return res.end(JSON.stringify({ errors: validationErrors }))
  13.   }

  14.   // Build the context and execute
  15.   const context = await contextFactory(req)
  16.   const result = await execute({
  17.     document,
  18.     schema,
  19.     variableValues: variables,
  20.     contextValue: context
  21.   })

  22.   // Send the response
  23.   res.end(JSON.stringify(result))
  24. })

  25. httpServer.listen(3000)
  26. ```

Behind the scenes, this simple workflow allows you to use Envelop plugins and hook into the entire request handling flow.

Here's a simple example for collecting metrics and log all incoming requests, using the built-in plugins:

  1. ```ts
  2. const getEnveloped = envelop({
  3.   plugins: [useEngine(GraphQLJS), useSchema(schema), useLogger(), useTiming()]
  4. })
  5. ```




Available Plugins


You can explore all plugins in our Plugins Hub. If you wish your plugin to be listed here and under PluginsHub, feel free to add your plugin information in this file and create a Pull Request!

We provide a few built-in plugins within the @envelop/core, and many more plugins as standalone packages.


Sharing / Composing envelops


After an envelop has been created, you can share it with others as a complete layer of plugins. This is useful if you wish to create a predefined layer of plugins, and share it with others. You can use it as a shell and as a base for writing shareable pieces of servers.

You can read more about Sharing and Composing Envelops here.

Write your own plugin!


Envelop plugins are just objects with functions, that provide contextual implementation for before/after of each phase, with a flexible API.

Here's a simple example that allows you to print the execution params:

  1. ```ts
  2. const myPlugin = {
  3.   onExecute({ args }) {
  4.     console.log('Execution started!', { args })

  5.     return {
  6.       onExecuteDone({ result }) {
  7.         console.log('Execution done!', { result })
  8.       }
  9.     }
  10.   }
  11. }

  12. const getEnveloped = envelop({
  13.   plugins: [
  14.     /// ... other plugins ...,
  15.     myPlugin
  16.   ]
  17. })
  18. ```


Contributing


If this is your first time contributing to this project, please do read our Contributor Workflow Guide before you get started off.

Feel free to open issues and pull requests. We're always welcome support from the community.

Code of Conduct


Help us keep Envelop open and inclusive. Please read and follow our [
of Conduct](https://github.com/the-guild-org/Stack/blob/master/CODE_OF_CONDUCT.md) as adopted from Contributor Covenant

License

GitHub license

MIT