If you're working with GraphQL, there's a good chance you've either heard of or are using graphql-tools.
One of the many cool things graphql-tools does for you is allow you to describe your schema as a GraphQL type language string and your resolvers as an object literal with all the resolver methods (check the example section of their readme to see how this works).
There's a problem though: what happens when you start having hundreds of type definitions and resolvers? As you can imagine, managing a single type definitions string and a single object literal for a growing project means you're soon going to deal with files that are thousands of lines long. Not ideal.
GraphQL Bundler allows you to split your type definitions and resolver functions in as many files and directories as you'd like: the bundling functions will merge it all back for you.
Here's a very simple feature centric example structure:
- your-api/
|__ src/
|__ user/
| |__ user.graphql
| |
| |__ signup/
| | |__ signup.graphql
| | |__ signup.js
| |
| |__ login/
| |__ login.graphql
| |__ login.graphql
In the above example, the user.graphql
file may contain your generic user type definition/s, whereas your signup.graphql file may contain a few specific input types related to the signup feature.
The javascript files, on the other hand, would export an object literal that would look like this:
module.exports = {
Query: {
exampleQuery: () => {}
},
Mutation: {
exampleMutation: () => {}
},
Subscription: {
exampleSubscription: () => {}
}
}
In the case of our example, signup.js
could look something like this:
module.exports = {
Mutation: {
signup: () => {}
}
}
This is only an example structure. You can organise your type definitions and resolvers files in any way you see fit.
Installing GraphQL Bundler is super easy:
npm install --save graphql-bundler
and including it in your project is just as easy:
const { getBundledGraphQLTypeDefs, getBundledGraphQLResolvers } = require('graphql-bundler')
// do your thing
- Install GraphQL Bundler:
npm install --save graphql-bundler
. - Create your graphql type definition and resolver files.
- Make sure your
.graphql files
contain nothing but valid GraphQL type definitions. - Make sure your
.js resolver files
export an object literal containing onlyQuery
,Mutation
andSubscription
as top level properties, each with valid methods within them. - Once you have all your type definition files and resolver files in place, you are ready to generate the bundle.
Here's a quick example:
// make sure to include graphql-tools in your project!
const { makeExecutableSchema } = require('graphql-tools')
const { getBundledGraphQLTypeDefs, getBundledGraphQLResolvers } = require('graphql-bundler')
const executableSchema = makeExecutableSchema({
typeDefs: getBundledGraphQLTypeDefs('./path/to/your/graphql/files/**/*.graphql'),
resolvers: getBundledGraphQLResolvers('./path/to/your/resolver/files/**/*.js')
})
Essentially, the two bundler functions exported by GraphQL Bundler do the following:
- They take a glob as argument.
- They retrieve all the files matching the glob passed as argument.
- They validate the contents of those files to make sure they are valid type definitions and resolvers.
- They bundled them together while doing additional things like checking for duplicates.
- They return the bundled type definitions and resolvers.
I wanted to have a better directory structure for the GraphQL projects I work on :)