Graphql-tools: Can I split queries and mutators across different files?

Created on 25 Oct 2016  路  14Comments  路  Source: ardatan/graphql-tools

I'm trying to break up my schema into Entity specific classes, where each class defines the types, queries, mutators and resolvers specific to that Entity. Is this possible?

From the example, I can see that you can split Types and their resolves into seperate Entity specific files, but not queries/mutators?

Thanks

Initially incorrectly posted here https://github.com/apollostack/graphql-server/issues/190

question

Most helpful comment

I didn't even realize we had this feature, but apparently we support the extend type syntax, but it's just not documented: https://github.com/apollostack/graphql-tools/pull/90/files

Perhaps someone can put together an example of how to us this to extend Query with extra fields?

All 14 comments

I had similar questions and took some time to organize files for graphql server. Therefore I made an example of file/folder structure for an example of an API server based on graphql.

Take a look here https://github.com/tadejstanic/graphql-api-example and maybe you can find some ideas. Contributions are welcome.

I didn't even realize we had this feature, but apparently we support the extend type syntax, but it's just not documented: https://github.com/apollostack/graphql-tools/pull/90/files

Perhaps someone can put together an example of how to us this to extend Query with extra fields?

@stubailo I've just included the extend type example. It's great to have this feature which brings another option for a better graphql files organization and code consolidation.

https://github.com/tadejstanic/graphql-api-example

@dcworldwide you can take a look at how i leveraged grahpql-tools to generate schema from couple of modules (https://github.com/DxCx/webpack-apollo-server/tree/master/src/schema)

Would someone be able to contribute docs about the extend feature?

@dxcx will that allow you to split queries across files though?

@dcworldwide yes, you can see the logic there that connects couple of modules into Query.
it is leveraging graphql-tools's ability to build schema from object of resolvers and shards of typedef

This looks like a pretty cool solution: https://github.com/graphql/graphql-js/issues/223#issuecomment-258994035

https://github.com/graphql/graphql-js/issues/223#issuecomment-258994035

@liamcurry's graphql-merge is exactly what I imagine happening under the hood for makeExecutableSchema({ typeDefs: [] }). I think it's an elegant answer to this question. If makeExecutableSchema merged strings intelligently, then importing pieces of your schema from other files and splatting them together would be trivial.

Is the extend type approach bad? I feel like merging strings isn't really a good long-term solution especially if the schema language improves over time.

New graphql developer here but I really like the extend type keyword since:
a) It appears to be part of the language spec.
b) It's implemented in graphql-python, graphql-js, sangria-graphql (Scala)
c) It's a piece of piss to use.

My solution:

session/schema.js

import { sessionLogin$, sessionLogout$, sessionRegistration$ } from '../session'

export const typeDefs = [
  `type Session {
    id: ID!
  }`
]

export const query = [
]

export const mutation = [
  `sessionLogin(
    email: String!,
    password: String!
  ): Session`,
  `sessionLogout(
    sessionId: ID
  ): Boolean`,
  `sessionRegistration(
    email: String!
  ): Boolean`
]

export const resolvers = {
  Mutation: {
    sessionLogin: async (parent, { email, password }, { res }) => {
      try {
        return await sessionLogin$({ email, password, res })
      } catch (err) {
        throw new Error(`Cannot login`)
      }
    },

    sessionLogout: async (parent, { sessionId }, { req, res }) => {
      try {
        if (sessionId) {
          sessionLogout$({ sessionId, res })
        } else if (req && req.cookies.sessionId) {
          sessionLogout$({ sessionId: req.cookies.sessionId, res })
        }
        return true
      } catch (err) {
        throw new Error(`Cannot logout`)
      }
    },

    sessionRegistration: async (parent, { email }, ctx) => {
      return sessionRegistration$({ email })
    },
  }
}

graphql.js

import { makeExecutableSchema } from 'graphql-tools'
import { merge } from 'lodash'
import { typeDefs, resolvers, query } from './schema'

let typeDefsList = [ ...typeDefs ]
let resolversList = [ resolvers ]
let queryList = [ query ]
let mutationList = []

export function add({ typeDefs, resolvers, query = [], mutation = [] }) {
  typeDefsList.push(...typeDefs)
  resolversList.push(resolvers)
  queryList.push(...query)
  mutationList.push(...mutation)
}

export function getSchema() {
  return makeExecutableSchema({
    typeDefs: [
      ...typeDefsList,
      `type Query { ${ queryList.join('\n') } }`,
      `type Mutation { ${ mutationList.join('\n') } }`
    ],
    resolvers: merge(...resolversList)
  })
}

I happened across a new use case for a strict merging that would be better than the extend syntax.

I have multiple modules in my project that all specify additional fields/constraints on a certain piece of data. That data is a single entity in our domain language, and so is treated as such in our backend.

So when we do an insert for that complex data type, we run onto problems as you cannot extend input types.

I'm currently looking into the string merging solution for now...

Was this page helpful?
0 / 5 - 0 ratings