Envelop is a lightweight GraphQL plugin library that allows you to add customized features to your GraphQL execution layer regardless of the GraphQL server you use.
GraphQL servers like Apollo GraphQL and Graphite already have platform-specific plugin systems that work well. The downside is that if you choose to move to a different implementation of GraphQL for any reason, you will need to modify the plugin to work with that specific implementation.
That’s where Envelop comes in. Envelop is not a GraphQL server — it’s a wrapper on GraphQL that allows developers to write platform-independent plugins. This means you only need to write your plugin once in order for it to work with Envelop and integrate into any GraphQL server.
To learn how to accomplish this, we’ll integrate Envelop with Fastify and Apollo GraphQL.
Here’s what you’ll need to follow along with this tutorial:
Run the following command to install all the dependencies we’ll need:
npm install @envelop/core fastify graphql graphql-helix --save
Next, we need to create a server. Create a server.js
file and add the following code:
const { envelop, useSchema, useLogger } = require('@envelop/core'); const fastify = require('fastify'); const { processRequest, getGraphQLParameters } = require('graphql-helix');
In the code above, we’re importing envelop
and its plugins. If you have used React Hooks, the naming convention for the plugins will be familiar to you. Envelop plugins are named with a prefix and the use
keyword. In this example, we’ll add both the useSchema
and the useLogger
plugin.
For starters, we’ll use GraphQL Helix to build our GraphQL server to catch and process requests to the Fastify server.
Next, we’ll create a schema.js
file, where we’ll define our schema types, mutations, and resolvers so that we can create a library of songs. This file should have the following content:
const { GraphQLObjectType, GraphQLSchema, GraphQLString, } = require("graphql"); const schema = new GraphQLSchema({ mutation: new GraphQLObjectType({ name: "Mutation", fields: () => ({ echo: { args: { text: { type: GraphQLString, }, }, type: GraphQLString, resolve: (_root, args) => { return args.text; }, }, }), }), query: new GraphQLObjectType({ name: "Query", fields: () => ({ song: { type: new GraphQLObjectType({ name: "Song", fields: () => ({ firstVerse: { type: GraphQLString, resolve: () => "Singing me a song is lovely.", }, secondVerse: { type: GraphQLString, resolve: () => new Promise((resolve) => setTimeout( () => resolve("You never wanted to sing with me?"), 5000 ) ), }, }), }), resolve: () => ({}), }, }), }), }); module.exports = schema
We’ll import the schema we just created and use it just after our Helix library import in server.js
, as shown below:
const { envelop, useSchema, useLogger } = require('@envelop/core'); const fastify = require('fastify'); const { processRequest, getGraphQLParameters } = require('graphql-helix'); const mySchema = require("./mySchema"); //here
No matter what GraphQL server and integration process you are using, the next step is fairly simple. In our example, we are using two plugins, useSchema()
and useLogger()
. You can use as many plugins as you want — you’ll just need to add the plugin to the plugins
array, like so:
const getEnveloped = envelop({ plugins: [useSchema(mySchema), useLogger()], });
This is a key part of the integration because it gives you a high level of abstraction and allows you to de-couple the required components for use.
Next, we’ll need to create a Fastify app and integrate Envelop.
const fastifyApp = fastify(); const port = 3000; fastifyApp.route({ method: ['POST'], url: '/graphql', async handler(req, res) { const { parse, validate, contextFactory, execute, schema } = getEnveloped({ req, }); const request = { body: req.body, headers: req.headers, method: req.method, query: req.query, }; const { operationName, query, variables } = getGraphQLParameters(request); const result = await processRequest({ operationName, query, variables, request, schema, parse, validate, execute, contextFactory, }); if (result.type === 'RESPONSE') { res.status(result.status); res.send(result.payload); } else { res.send({ errors: [{ message: 'Not Supported' }] }); } }, }); fastifyApp.listen(port, () => { console.log(`GraphQL server is running on port:`, port); });
Let’s break down this code. We first set up the server and configured the GraphQL endpoint. Then we imported parse
, contextFactory
, execute
, and schema
from the Envelop instance, as shown below:
const { parse, validate, contextFactory, execute, schema } = getEnveloped({req});
These are some of the parameters from Envelop that we’ll pass to Helix to process our GraphQL requests.
const result = await processRequest({ operationName, query, variables, request, schema, parse, validate, execute, contextFactory, });
Now we can run the API with the node server.js
command to start the Node server.
We should test out our app using Postman.
That’s it! We’ve successfully integrated Envelop and added a custom plugin to a Node application.
Like I mentioned earlier, you can integrate Envelop with any GraphQL server. Let’s see an implementation with Apollo GraphQL.
In a separate directory, install GraphQL, Apollo, and GraphQL Tools by running the command below:
npm install @apollo/client graphql @graphql-tools/schema
Create a separate JavaScript file called app.js
and add the following code to it.
import { ApolloServer } from 'apollo-server'; import { envelop, useSchema, useLogger } from '@envelop/core'; import { makeExecutableSchema } from '@graphql-tools/schema'; const schema = makeExecutableSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String! } `, resolvers: { Query: { hello: () => 'World', }, }, }); const getEnveloped = envelop({ plugins: [useSchema(schema), useLogger()], }); const server = new ApolloServer({ executor: async requestContext => { const { schema, execute, contextFactory } = getEnveloped({ req: requestContext.request.http }); return execute({ schema: schema, document: requestContext.document, contextValue: await contextFactory(), variableValues: requestContext.request.variables, operationName: requestContext.operationName, }); }, }); server.listen(3000);
In the above snippet, we created an executable schema with GraphQL Tools, created an instance with Envelop, and added the useSchema()
and the useLogger()
plugins.
const getEnveloped = envelop({ plugins: [useSchema(schema), useLogger()], });
Note that useSchema
and useLogger
both come prepackaged with Envelop.
Finally, in the Apollo server object, override the executor object with parameters from the Envelop object. That’s all you need to integrate Envelop with your Apollo GraphQL server.
If you build applications with GraphQL, you’ll find Envelop to be a great addition to your project. This is especially true if you like to keep your code DRY, as Envelop allows you to write modular GraphQL plugins that work on all GraphQL server implementations. Thanks for reading!
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowSOLID principles help us keep code flexible. In this article, we’ll examine all of those principles and their implementation using JavaScript.
JavaScript’s Date API has many limitations. Explore alternative libraries like Moment.js, date-fns, and the new Temporal API.
Explore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.
One Reply to "Configuring any GraphQL server with Envelop"
npm install @apollo/client graphql @graphql-tools/schema
Little typo, you must install apollo-server