prisma-labs / graphql-framework-experiment

Code-First Type-Safe GraphQL Framework
https://nexusjs.org
MIT License
675 stars 66 forks source link

Resolver middleware #633

Open jasonkuhrt opened 4 years ago

jasonkuhrt commented 4 years ago

Perceived Problem

Ideas / Proposed Solution(s)

Weakky commented 4 years ago

Status update

A first iteration is now in the pipeline in #688. This iteration intentionally provides very little abstraction over the @nexus/schema middleware system.

There's a number of ways we could enhance the current API by providing a higher level abstraction.

The current API looks like this:

schema.middleware((config) => {
  // Can return `undefined` before returning the middleware to skip its creation
  // eg: To exclude `Query` from the middleware, you would do:
  // if (config.parentTypeConfig.name === 'Query') { return }

  return async (root, args, ctx, info, next) {
    // Middleware implementation
  }
})

Abstracting even more onCreateFieldResolver

The API could look like this

schema.middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
})

Type selection API

By abstracting the underlying API even more, we lost the ability to skip the creation of a resolver. We therefore need some API to be able to optionally select on which type to apply the middleware. Here are some ideas:

a. Fluent API

// Apply only on Query and Mutation type
schema.middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
}).only('Query', 'Mutation')
// Apply on all types except Query and Mutation
schema.middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
}).except('Query', 'Mutation')

Pros/cons:

b. Option API

// Apply only on Query and Mutation type
schema.middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
}, {
  only: ['Query', 'Mutation']
})
// Apply on all types except Query and Mutation
schema.middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
}, {
  except: ['Query', 'Mutation']
})

Pros/cons:

c. Fluent API v2

// Apply only on Query and Mutation type
schema.pick('Query', 'Mutation').middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
})
// Apply on all types except Query and Mutation
schema.omit('Query', 'Mutation').middleware(async (root, args, ctx, info, next, config) => {
  // Your middleware
}).except('Query', 'Mutation')

Note: We could use only and except instead of pick and omit

Pros/cons:

Type selection capabilities

Furthermore, we could make the type selection go beyond just string matching, and allow regex patterns to match type names.

eg:

.only('Query', 'User', /Stripe.*/, 'Stripe*')