How to Setup and Structure Your GraphQL Project
In this blog, you will learn how to set up a graphql project for production. Also, you will learn how to split your type definitions and resolvers into different file types.
Note
I will assume you have a basic idea of graphql. We won't build any serious projects. I will teach you with some dummy examples. But if you know the basics, you will be able to apply them in your project.
Video Tutorial
Please check the video to get a better understating.
Setup
Install packages.
1npm install @apollo/server graphql lodash2npm install --save-dev @babel/cli @babel/core @babel/node @babel/preset-env nodemon
Explanation:
- @apollo/server, graphql: For graphql
- Lodash: Utils library
- @babel/core: Babel is a transcompiler that compiles js code based on the given configuration. The babel does not do anything. Plugins do.
- @babel/preset-env: Preset is a combination of a bunch of plugins. This preset will allow us to use next-generation javascript code. Then it will be compiled down to browser and nodejs compatible code. It also adds many features.
- nodemon: nodemon is a tool to restart the server automatically whenever we change our source code so that we don't have to do it manually.
Setup babel and scripts
- Create a .babelrc file and add the config
1{2 "presets": ["@babel/preset-env"]3}
- Add the following scripts to
package.json
1{2 "scripts": {3 "dev": "nodemon --exec babel-node src/index.js",4 "build": "babel src -d build",5 "start": "npm run build && node build/index.js"6 }7}
Let's explore the scripts:
- dev: This script will be used to start the development server.
nodemon
will automatically start the server when our code changes. But even before thatnodemon
will executebabel-node
and will compile thesrc/index.js
file. - build: This script will be used for
production
.babel
will compile our code from thesrc
folder to the build directory.babel
will automatically create a build directory for you if it does not exist. - start: I will first run our build script. Then it will start our node server from the build directory.
Setup graphql
Let's set up a simple graphql server. We will put the following code in the src/index.js
file.
1import { ApolloServer } from '@apollo/server'2import { startStandaloneServer } from '@apollo/server/standalone'34const books = [5 {6 title: 'The Awakening',7 author: 'Kate Chopin',8 },9 {10 title: 'City of Glass',11 author: 'Paul Auster',12 },13]1415const typeDefs = `#graphql16 type Book {17 title: String18 author: String19 }2021 type Query {22 books: [Book]23 }24`2526const resolvers = {27 Query: {28 books: () => books,29 },30}3132;(async () => {33 const server = new ApolloServer({34 typeDefs,35 resolvers,36 })3738 const { url } = await startStandaloneServer(server, {39 listen: {40 port: 5000,41 },42 })4344 console.log(`🚀 Server ready at: ${url}`)45})()
Explanation:
- We have the type definition in
typeDefs
and resolvers inresolvers
. - The book query type will return the array of books.
- In the iife, we have created a new instance of
ApolloServer
- Then we run the server instance with the
startStandaloneServer
method.
Test
- Now run the server using
npm run dev
. You should not have any errors. - Then go to http://localhost:5000/ and you should see the graphql playground.
This is how you can set up a graphql project. Now let me show you how you can structure your GraphQL codebase into different files and directories.
Structuring graphql project
Note: There is no standard way of structuring a graphql project. You don't have to strictly follow it. You can get the basic idea from here and then you can use that in your project.
- Let's create a directory inside
src/
- Create two more files inside the graphql directory
- resolvers.js: It will store all the resolvers inside a single object
- typeDefs.js: It will store all the type definitions inside an array
1mkdir graphql2touch resolvers.js typeDefs.js
Suppose we are building a social media application.
So, we will create more directory-based features or services. For example, A social media app has users. Users can log in, log out, register, etc. So, we will create a directory for users. Then you can create directories for profiles, posts, and so on. We will just use the user/
directory.
Inside the user/
directory will create few more files. There we will put all user related typedefs and resolvers.
1touch userResolvers.js userTypeDefs.js
- userTypeDefs.js
1const type = `#graphql2 type User {3 name: String4 country: String5 }67 extend type Mutation {8 registerUser(name: String): User9 loginUser(name: String): User10 logOutUser(name: String): User11 }12`1314export default type
Explanation:
- We have user type and some Mutations which will return User type.
- Note that we are extending the
Mutation
type. There can be only oneQuery
andMutation
type. - Then we export that type
Now, we will create another file authenticateUser.js
Where we will put auth related mutation resolvers.
- authenticateUser.js
1const registerUser = (_, { name }) => {2 // action3 return { name }4}56const loginUser = (_, { name }) => {7 // action8 return { name }9}1011const logOutUser = (_, { name }) => {12 // action13 return { name }14}1516const resolvers = {17 Mutation: {18 registerUser,19 loginUser,20 logOutUser,21 },22}2324export default resolvers
Explanation:
- We first create resolvers object where we will have a Mutation(or Query) property.
- Inside that we will put all of our resolvers function. Make sure the property names match with the mutation types.
- userResolvers.js
1import merge from 'lodash/merge'23import authenticateUser from './authenticateUser'45const userResolvers = merge(authenticateUser)67export default userResolvers
Explanation:
- First we import all the user resolvers
- Then we merge them inside an single object and export that.
- Let's go to
src/graphql/typedefs.js
file.
1import userTypeDefs from './user/userTypeDefs'23const initialTypeDefs = `#graphql4 type Query {5 _empty: String6 }78 type Mutation {9 _empty: String10 }11`1213const typeDefs = [initialTypeDefs, userTypeDefs]1415export default typeDefs
Explanation:
- We are creating the initial
Query
andMutation
type. - Like I have mentioned before, there can be only one
Query
andMutation
type and we always extend them. - We create a new array
typedefs
. We add all the typedefs to the to that array.
src/index.js
1import { ApolloServer } from '@apollo/server'2import { startStandaloneServer } from '@apollo/server/standalone'34import typeDefs from './graphql/typeDefs'5import resolvers from './graphql/resolvers'6;(async () => {7 const server = new ApolloServer({8 typeDefs,9 resolvers,10 })1112 const { url } = await startStandaloneServer(server, {13 listen: {14 port: 5000,15 },16 })1718 console.log(`🚀 Server ready at: ${url}`)19})()
Explanation:
- Now, we just import that typedefs and resolvers and add them to the
ApolloServer
instance.
Final Code structure
Again you don't have to follow the exact same structure.
1├── package.json2├── package-lock.json3└── src4 ├── graphql5 │  ├── resolvers.js6 │  ├── typeDefs.js7 │  └── user8 │  ├── authenticateUser.js9 │  ├── userResolvers.js10 │  └── userTypeDefs.js11 └── index.js
Shameless Plug
I have made an Xbox landing page clone with React and Styled components. I hope you will enjoy it. Please consider like this video and subscribe to my channel.
That's it for this blog. I have tried to explain things simply. If you get stuck, you can ask me questions.
Contacts
- Email: thatanjan@gmail.com
- LinkedIn: @thatanjan
- Portfolio: anjan
- Github: @thatanjan
- Instagram : @thatanjan
- Twitter: @thatanjan
Blogs you might want to read:
- Eslint, prettier setup with TypeScript and react
- What is Client-Side Rendering?
- What is Server Side Rendering?
- Everything you need to know about tree data structure
- 13 reasons why you should use Nextjs
- Beginners guide to quantum computers
Videos might you might want to watch: