
Back Story
At work, we are rebuilding the entire API system using Nodejs, GraphQL, and gRPC. Doing research for the last couple of months, I have been noticing a lack of articles using Nodejs with GraphQL, so I’ll be starting a series of graphQL and Nodejs on how to do certain things that took us a while to figure out. I hope to release one article per month and if it at least helps one person, then I think the article has done its job. Lets get started with modularizing (stitching) the graphQL schema.
From the gecko, we knew that our graphQL schema was going to keep growing and growing the more we developed our API. We found some articles on how to do it with lodash and other libraries but we didn’t want to clutter our application with more dependencies, so we kept searching for a better way. Thankfully, we stumbled upon a tool called graphql-tools.
Lets say we have the following schema in a single file
We are using apollo-server
// app.jsconst { ApolloServer, gql } = require('apollo-server');const typeDefs = gql`
type Query {
getBooks: [Book]
getUsers: [User]
} type Book {
title: String
author: String
} type User {
email: String
password: String
}
`;const resolvers = {
Query: {
getBooks: () => books,
getUsers: () => users,
},
};const server = new ApolloServer({typeDefs, resolvers});server.listen().then(({url}) => {
console.log(`🚀 Server ready at ${url}`);
});
Assume books and users are objects that are populated with the correct data.
Obviously, this is a very small schema, so there is no need to separate the type definitions, but lets say we wanted to. In order to accomplish this, you must install graphql-tool into your existing project with the command:
npm install --save graphql-toolsWith this module, we’ll have access to the makeExecutableSchema function which will take care of the stitching for us. Now, lets refactor our code.
Separating the Schema
// book.typedefs.js
module.exports.bookTypeDefs = {
extend type Query {
getBooks: [Book]
}
type Book {
title: String
author: String
}
};You can learn more about the extend keyword here
And we also have:
// user.typeDefs.jsmodule.exports.userTypeDefs = {
extend type Query {
getUsers: [User]
} type User {
email: String
password: String
}
};
For our project, we decided to keep resolvers and type definitions in their own separate file to have cleaner code and we realized this will make debugging easier.
// book.resolvers.jsconst { books } = require('./fakeDB.js');module.exports.bookResolvers = {
Query: {
getBooks: (parent, args, context, info) => {
return books;
},
},
};
And now for the users resolvers:
// user.resovlvers.js
const { user } = require('./fakeDB.js');module.exports.userResolvers = {
Query: {
getUsers: (parent, args, context, info) => {
return users;
},
},
};
Stitching It Back Together
Now that we separated our type definitions, we can easily import into a single file. Lets called this file scheme.js
// schema.jsconst { gql } = require('apollo-server');// IMPORT TYPE DEFINITIONS
const { bookTypeDefs } = require('./book.typedefs');
const { userTypeDefs } = require('./user.typeDefs');// IMPORT RESOLVERS
const { bookResolvers } = require('./book.resolvers');
const { userResolvers } = require('./user.resolvers');const Query = gql`{
type Query {
__empty: String
}
}`;const resolvers = {
Query: Object.assign({}, bookResolvers.Query, userResolvers.Query);
}module.exports.schema = makeExecutableSchema({
typeDefs: [Query, bookTypeDefs, userTypeDefs],
resolvers,
});
Now, we have the schema to pass back into ApolloServer! So, let’s see how that looks.
// app.jsconst { ApolloServer, gql } = require('apollo-server');
const { schema } = require('./schema');
const server = new ApolloServer({ schema });server.listen().then(({url}) => {
console.log(`🚀 Server ready at ${url}`);
});
Now you can run node app.js in the terminal and it should work!
Conclusion
I know this was a simple example, but can be used to simplify complex projects. As your graphql type definitions and resolvers increase, it is going to get a lot harder to debug and maintain the code. Thank you for reading it, I hope this was helpful. And please let me know if I made a mistake somewhere along the way or you have question about any part of the article. I’ll try to make a short tutorial for lodash.merge :)
