Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execute against different schemas based on request headers #913

Closed
curtiswilkinson opened this issue Nov 14, 2022 · 8 comments · Fixed by #979
Closed

Execute against different schemas based on request headers #913

curtiswilkinson opened this issue Nov 14, 2022 · 8 comments · Fixed by #979
Labels
documentation enhancement New feature or request help wanted Extra attention is needed

Comments

@curtiswilkinson
Copy link
Contributor

I have a scenario where based on a request header coming from the client, the query should be executed against a completely seperate GraphQL Schema.

req.header.schema === 'A' -> execute against schema A
req.header.schema === 'B' -> execute against schema B

I've handled this situation in a number of other GraphQL implementations, and was interested in using Mercurius if it's straight-forward.

Apologies if this is an obvious question or if it's more related to fastify (which I admittedly have very little experience with). I've done some digging and couldn't see a straight-forward way without doing something very hand-rolled.

I'd appreciate any guidance if you have any! I'd love to use Mercurius, as the benchmarking I've done has been very positive.

@mcollina
Copy link
Collaborator

This question is fairly not obvious and something that Mercurius should support better.

This could be managed via Fastify Constraints and plugin encapsulation. Essentially you'd register two instances of Mercurius, adding different routes with different constraints.

I would recommend to enable GraphiQL on only one of those multiple plugins.

I have never done this myself, so you'd possibly be on uncharted territory with bugs to fix.

@mcollina mcollina added enhancement New feature or request help wanted Extra attention is needed documentation labels Nov 14, 2022
@curtiswilkinson
Copy link
Contributor Author

Thanks @mcollina, it was pretty straight-forward with those keywords! The only unexpected thing was requiring routes: false due to the routes mercurius registers conflicting.

I haven't tested this extensively yet outside of just using the schema header to toggle introspection queries, but it appears to work nicely. I'll report back if there are any other problems I encounter/solve.

Let me know if you'd like me to create a PR to add this to the examples (and any adjustments/commentary you'd like), not sure how frequently it'd be encountered.

'use strict'

const Fastify = require('fastify')
const mercurius = require('..')

const schemaStrategy = {
  name: 'schema',
  storage: function () {
    const handlers = {}
    return {
      get: (type) => { return handlers[type] || null },
      set: (type, store) => { handlers[type] = store }
    }
  },
  deriveConstraint: (req, ctx) => {
    return req.headers.schema
  },
  validate: () => true,
  mustMatchWhenDerived: true
}

const app = Fastify({ constraints: { schema: schemaStrategy } })

const schema = `
  type Query {
    add(x: Int, y: Int): Int
  }
`

const resolvers = {
  Query: {
    add: async (_, obj) => {
      const { x, y } = obj
      return x + y
    }
  }
}

app.register(async childServer => {
  childServer.register(mercurius, {
    schema,
    resolvers,
    graphiql: false,
    routes: false
  })

  childServer.route({
    path: '/',
    method: 'POST',
    constraints: { schema: 'A' },
    handler: (req, reply) => {
      const query = '{ add(x: 2, y: 2) }'
      return reply.graphql(query)
    }
  })
})

const schema2 = `
  type Query {
    subtract(x: Int, y: Int): Int
  }
`

const resolvers2 = {
  Query: {
    subtract: async (_, obj) => {
      const { x, y } = obj
      return x - y
    }
  }
}

app.register(async childServer => {
  childServer.register(mercurius, {
    schema: schema2,
    resolvers: resolvers2,
    graphiql: false,
    routes: false
  })

  childServer.route({
    path: '/',
    method: 'POST',
    constraints: { schema: 'B' },
    handler: (req, reply) => {
      const query = '{ subtract(x: 10, y: 5) }'
      return reply.graphql(query)
    }
  })
})

app.listen({ port: 3000 })

@smolinari
Copy link
Contributor

Out of curiosity, how many different schemas will there be?

Scott

@curtiswilkinson
Copy link
Contributor Author

Somewhere between 1 and ~30 different schemas will be in place, it changes on a case-by-case basis

@smolinari
Copy link
Contributor

@curtiswilkinson - Is it for some sort of multi-tenancy system? And, are you trying to switch to Mercurius because the other GraphQL servers were slow with this setup?

Scott

@curtiswilkinson
Copy link
Contributor Author

@smolinari it is along these lines yes!
The performance we've gotten through other solutions has been "adequate", but it's taken a lot of work and hand-rolled parts over the years to keep it that way.

The goal of this investigation is to see if Mercurius generally makes sense as a next step and if it allows us to shed some of our older home-grown parts (which so far appears to be the case).

@simoneb
Copy link
Collaborator

simoneb commented Dec 15, 2022

@curtiswilkinson I would be interested to read about the outcome of the work you've done in this area. Ideally this outcome is captured in the docs because I assume that other people may want to set up something similar, and having a guide showing them how to do this would be quite useful. Do you have any appetite for putting something like this together?

@brainrepo
Copy link
Contributor

Hi folks, I create a simple pr for adding this case to the examples folder and in the FAQ docs section #979. Happy to know your opinion.

simoneb added a commit that referenced this issue Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants