Skip to main content

Modern API Development (Part 3) : Add GraphQL

· 5 min read
Mitch Chimwemwe Chanza

This post is a follow-up to the previous one at Part 2: Initiating Server. If you're looking to integrate GraphQL into an existing REST API, this guide is tailored for you. For those aiming to incorporate GraphQL into a new REST API, please refer to the instructions provided in the earlier posts.

I'm delighted that you've reached this point, and I hope you're finding the journey enjoyable. As we continue with this series, there's still much more ground to cover. Now, let's shift our focus to the modernization of the API. I understand if you've been pondering, "What's considered modern about this server?" especially since it relies on the trusted 'express.' Take a moment to relax because you're about to delve into the contemporary aspects of this series.

we are going to cover the following topcs in this guide:

  • Install additional dependencies - GraphQl Tools, Apollo Server 4
  • Reconfigure the API to have separate routes, one for Graphql and one for REST
  • Implement GraphQL Endpont and resolvers
  • Test the API

Alright, no more talking – let's jump right in!

add graphql dependencies
# install all dependencies for graphql to work in our API
pnpm api add graphql @apollo/server @graphql-tools/load @graphql-tools/graphql-file-loader

The graphql package is now installed. we can proceed to configure our API. firstly we need to create a graphql folder in the api folder. this is where our graphql files will be stored. i will create a main.graphql file in that folder.

We are going to have three types initialized in this file:

  • Response - custom type for responses
  • Query - required root graphql query type
  • Mutation - required root mution type
api/graphql/main.graphq file
type Response {
message: String!
success: Boolean!
error: String

type Query {
hello: String

type Mutation {
hello: String

Up next we need to move some code from main.ts to be isolated to their own module. i am refering to the router which is set inside the main file.

api/src/main.ts file
// ... rest of code
const router = express.Router();
// Set initial route
router.get("/", (_req, res) => {
res.send({ message: "Monorepo API Configured!", success: true});
// .. rest of code

We are moving this part to a separate module called api/src/endpoints/rest/restEndpoints.ts. where we will do some modifications and export the module

// api/src/endpoints/rest/restEndpoints.ts
import express, { Router } from "express";

const restEndpoint: Router = express.Router();
// define routes
restEndpoint.get("/", (_req, res) => {
res.send({ message: "Rest Endpoint Initialized!" });

export { restEndpoint }

Now lets updated api/src/main.ts to use the rest endpoint.

api/src/main.ts file
import { restEndpoint } from './endpoints';

// ... rest of code
// Set v1/api endpoint
app.use("/v1/api", restEndpoint);
// .. rest of code

As observed, the import originates from the ./endpoint module rather than ./endpoint/rest/restEndpoint. This is accomplished by incorporating a barrel file within the endpoints folder, which exports all submodule functionalities. read more on what a barrel file is here.

We can run our server again to be sure that we did not break anything.

run server
# run server
pnpm api dev
# our server should be running properly as expected.
# http://localhost:9100 or http://localhost:9000 depending on the PORT set in .env file

Hold on, this isn't GraphQL yet; we're still operating a REST API! yes you are right, its one of the steps toward adding multiple routes tou our API. Up next we are going to create another route for our API inside api/src/endpoints/graphql/graphqlEndpoints.ts module. Additionally we also need to create a resolver module api/src/endpoints/graphql/resolvers.ts which is going to be responsible for implementating all resolvers.

// api/src/endpoints/graphql/graphqlEndpoints.ts
import { ApolloServer } from '@apollo/server';
import { loadSchemaSync } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { resolvers } from '.';
// load schema from graphql files
const typeDefs=loadSchemaSync('./graphql/*.graphql', {
loaders: [
new GraphQLFileLoader()

// create apollo server
const server = new ApolloServer({

// export server
export { server}

please note this is a minimal configuration for now.

// api/src/endpoints/graphql/resolvers.ts

export const resolvers = {
Query: {
hello: () => `Hello there welcome to api monorepo`
Mutation: {
hello: (_: unknown, args: { name: string }) => `Hello ${} welcome to api monorepo`


A sigh of relief we are now ready to test our REST + GraphQL APIs running on the same server.

run server
# run server
pnpm api dev
# our server should be running properly as expected.
# http://localhost:9100/v1/rest and http://localhost:9000/v1/graphql

We can now happily commit our changes. and push them to our remote repository under the feature/part3 branch.