GraphQL Resolvers Middleware and Apollo Server Plugins
April 04, 2020
I recently came across a problem where I needed to perform some custom logic on the result of a GraphQL query before it’s returned to the client and now I’d like to share some of the possible solutions in Apollo Server and graphql-compose.
It’s important to understand whether resolver middleware can be used for the specific task or you will need Apollo Server-level middleware. Keep in mind that resolver middleware is run per resolver while some Apollo Server plugins will be run on the final result before it is sent back to the client. You can learn more on when resolver middleware will not be of help in my previous post.
Table of Contents
Resolver middleware:
- In graphql-compose you can use
wrapResolve
helper as follows:
import { schemaComposer } from "graphql-compose"
schemaComposer.Query.addFields({
someResolver: someResolverFunction.wrapResolve(next => async rp => {
// do something before the result
const result = await next(rp)
// do something after the result
return result
}),
})
- You can use
applyMiddleware
utility from graphql-middleware from Prisma Labs like so:
import { applyMiddleware } from "graphql-middleware"
const { ApolloServer } = require("apollo-server-express")
import { schema } from "./someSchema"
const someMiddleware = {
Query: {
someResolver: async (resolve, parent, args, context, info) => {
// do something before the result
const result = await resolve(parent, args, context, info)
// do something after the result
return result
},
},
}
const server = new ApolloServer({
schema: applyMiddleware(schema, userReviewsMiddleware),
...otherOptions,
})
willResolveField
which comes from graphql-extensions. I couldn’t find any documentation for this option but it exists. Better name for the extension would bedidResolveField
since it’s called after the field was actually resolved. This is how you can enable it:
const { ApolloServer } = require("apollo-server-express")
const server = new ApolloServer({
extensions: [
function middleware() {
return {
willResolveField(source, args, context, info) {
return (error, result) => {
if (error) {
// do something
}
// do something
return result
}
},
}
},
],
...otherOptions,
})
Response middleware in Apollo Server:
- The easiest option which requires minimal configuration is
formatResponse
which can be enabled like so:
const { ApolloServer } = require("apollo-server-express")
const server = new ApolloServer({
formatResponse: (result, ctx) => {
// do something
return result
},
...otherOptions,
})
- Apollo uses graphql-extensions package to allow us to hook into many stages of request execution via plugins. There’s nice documentation on this but some options are only mentioned here. It’s important to understand that request execution flow starts with
requestDidStart
so even if you’re interested in other plugins you still must userequestDidStart
to hook into the flow. Below is an example ofwillSendResponse
where you can change the response:
const { ApolloServer } = require("apollo-server-express")
const server = new ApolloServer({
plugins: [
{
requestDidStart(request) {
return {
willSendResponse(result, context) {
// do something
return {
graphqlResponse: result,
context,
}
},
}
},
},
],
...otherOptions,
})
In case you’re using willSendResponse
and formatResponse
simultaneously it’s worth noting that formatResponse
is executed before willSendResponse
.