Catch the highlights of GraphQLConf 2023! Click for recordings. Or check out our recap blog post.
Docs
Resolvers Composition

Resolvers Composition

Composition tool for GraphQL, with helpers to combine multiple resolvers into one, specify dependencies between fields, and more.

When developing a GraphQL server, it is common to perform some authorization logic on your resolvers, usually based on the context of a request. With Resolvers Composition you can easily accomplish that and still make the code decoupled - thus testable - by combining multiple single-logic resolvers into one.

The following is an example of a simple logged-in authorization logic:

Instead of doing this:

const resolvers = {
  Query: {
    myQuery(root, args, context) {
      // Make sure that the user is authenticated
      if (!context.currentUser) {
        throw new Error('You are not authenticated!')
      }
 
      // Make sure that the user has the correct roles
      if (!context.currentUser.roles || context.currentUser.roles.includes('EDITOR')) {
        throw new Error('You are not authorized!')
      }
 
      // Business logic
      if (args.something === '1') {
        return true
      }
 
      return false
    }
  }
}

You can do:

const { composeResolvers } = require('@graphql-tools/resolvers-composition')
 
const resolvers = {
  Query: {
    myQuery(root, args, context) {
      if (args.something === '1') {
        return true
      }
 
      return false
    }
  }
}
 
const isAuthenticated = () => next => (root, args, context, info) => {
  if (!context.currentUser) {
    throw new Error('You are not authenticated!')
  }
 
  return next(root, args, context, info)
}
 
const hasRole = (role: string) => next => (root, args, context, info) => {
  if (!context.currentUser.roles?.includes(role)) {
    throw new Error('You are not authorized!')
  }
 
  return next(root, args, context, info)
}
 
const resolversComposition = {
  'Query.myQuery': [isAuthenticated(), hasRole('EDITOR')]
}
 
const composedResolvers = composeResolvers(resolvers, resolversComposition)

composeResolvers is a method in @graphql-tools/resolvers-composition package that accepts IResolvers object and mappings for composition functions that would be run before resolver itself.

Supported Path Matcher Format

The paths for resolvers support * wildcard for types and glob patterns for fields. For example:

  • *.* - all types and all fields
  • Query.* - all queries
  • Query.single - only a single query
  • Query.{first, second} - queries for first/second
  • Query.!first - all queries but first
  • Query.!{first, second} - all queries but first/second