Apollo GraphQL Server ๐Ÿš€ With TypeScript

In this article, I am going to show how to build GraphQL express server with apollo server and typescript including unit test setup with jest. This can also use as a starter template to build apollo express server quickly and can be developed further for respective api requirement.

Let's start building this starter template project

Setting up the project

Create a new folder and start a project with package.json file

$ mkdir typescript-apollo-express-graphql-api
$ cd typescript-apollo-express-graphql-api
$ npm init --yesInstall & Initialize TypeScript

Install Typescript and generate a tsconfig.json file using npx. We will also need nodemon to compile our code on change, and ts-node to exec TypeScript files.

$ npm i typescript nodemon ts-node --save-dev
$ npx tsc --init --rootDir src --outDir dist --lib dom,es6 --module commonjs --removeComments

Setting up Express, Apollo and creating a simple GraphQL API

$ npm i apollo-server-express helmet compression cors express graphql http ncp graphql-tools
$ npm i @types/compression @types/express @types/graphql @types/node --save-dev

Create a /src directory with a server.ts file.

$ mkdir src && cd src && touch server.ts

If you are new to GraphQL, here is a link introducing GraphQL.

Creating GraphQL schema and resolvers

First, letโ€™s create our GraphQL Schema. In the /src folder, create a /service folder and 1file inside: /serviceSchema.ts

Define schema & query like this:

import { gql } from "apollo-server-express";

export const ServiceTypeDefs = gql`
  type User {
    name: String
  }
  type Query {
    getAllUsers: [User]
  }
`;

Let's create a graphQL resolver in \service folder in \serviceResolver.ts

import { ApolloError } from "apollo-server-express";
const ServiceResolvers = {
  Query: {
    getAllUsers: async (_: any, args: any) => {
      try {
        const mockUsers = [{ name: "xyz" }, { name: "abc" }];
        return mockUsers;
      } catch (error) {
        throw new ApolloError(error);
      }
    },
  },
};

export default ServiceResolvers;

Now we have to make a executable schema from the above schema & resolver. We will use makeExecutableSchema function from graphql-tools library. You can read more details in graphql-tools docs.

Create schema.ts in \src folder and write below code:

import { makeExecutableSchema } from "graphql-tools";
import { ServiceTypeDefs } from "./service/serviceSchema";
import serviceResolvers from "./service/serviceResolver";
import ServiceResolvers from "./service/serviceResolver";

export const schema = makeExecutableSchema({
  typeDefs: ServiceTypeDefs,
  resolvers: ServiceResolvers,
});

Setup server with express & apollo server

in our \server.ts file

import express from "express";
import { ApolloServer } from "apollo-server-express";
import { createServer } from "http";
import compression from "compression";
import cors from "cors";
import helmet from "helmet";
import { schema } from "./schema";

const PORT = process.env.PORT || 3000;
const app = express();
app.use("*", cors());
app.use(helmet());
app.use(compression());
const server = new ApolloServer({
  schema,
});
server.applyMiddleware({ app, path: "/graphql" });
const httpServer = createServer(app);
httpServer.listen({ port: PORT }, (): void =>
  console.log(`๐Ÿš€GraphQL-Server is running on http://localhost:3000/graphql`)
);

Last step: Compile the code

We have to adjust our script in package.json file.

"scripts": {
    "start": "node 'dist/server.js'",
    "build": "tsc -p . && ncp src dist",
    "test": "jest",
    "test:watch": "jest --verbose --detectOpenHandles",
    "start:dev": "npm run build:dev",
    "build:dev": "nodemon 'src/server.ts' --exec 'ts-node' src/server.ts -e ts,graphql"
  },

Aaaaandโ€ฆ Thatโ€™s it! Running $npm run build in your terminal will compile your code and put it in the /dist folder. Now run the compiled code with $npm run start

Open graphql playground on your localhost by opening http://localhost:3000/graphql in your browser. You can perform query in playground.

query{
  getAllUsers{
    name
  }
}

GraphQL Playground

Additional optional part (but most recommended to keep graphQL best practices) Unit Testing with jest:

For the best practice and keep consistent folder structure we can create a test folder inside each service folder(If you have multiple).

Create service.test.ts inside /src/service/test folder.

Install jest package:
$npm i jest ts-jest @types/jest --save-dev

create jest.config.js file in root directory of the project

module.exports = {
  globals: {
    "ts-jest": {
      tsConfig: "tsconfig.json",
    },
  },
  moduleFileExtensions: ["ts", "js"],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  testMatch: ["**/test/**/*.test.(ts|js)"],
  testEnvironment: "node",
  moduleNameMapper: {
    "src(.*)$": "<rootDir>/src/$1",
  },
};

Let's write a simple unit test in our service.test.ts file.

import { ServiceTypeDefs } from "../serviceSchema";
import ServiceResolvers from "../serviceResolver";
import { graphql } from "graphql";
import { makeExecutableSchema } from "graphql-tools";

// create a mocked schema for the tests
const schema = makeExecutableSchema({
  typeDefs: ServiceTypeDefs,
  resolvers: ServiceResolvers,
});

describe("User Schema", () => {
  test("Test getAllUsers query", async () => {
    const query = `
        {
            user: getAllUsers {
                name
            }
        }
    `;
    return graphql(schema, query).then((result: any) => {
      const users = result.data.user;
      expect(users.length).toBe(2);
    });
  });
});

The above query would simply check if the numbers of user return from query are exactly 2 or not. You can read more about testing with jest in jest documentation

Now let's adjust our script in package.json to automate unit testing with jest

"scripts": {
    "start": "node 'dist/server.js'",
    "build": "tsc -p . && ncp src dist",
    "test": "jest",
    "test:watch": "jest --verbose --detectOpenHandles",
    "start:dev": "npm run build:dev",
    "build:dev": "nodemon 'src/server.ts' --exec 'ts-node' src/server.ts -e ts,graphql"
  },

Now we can run all test with $npm run test and jest will automatically run all tests and display test results in terminal.

Screen-Shot-2021-01-31-at-6.47.02-PM

MISSION ACCOMPLISHED!!
Woohoo... We have made apollo server with typeScript. We can use it as a starter template to build powerful graphQL backend server.
Here is the github repo with all the code
I will soon add full series of Advanced Apollo Federation here so please follow US & stay upToDate.

Jaydeep Vachhani

Jaydeep Vachhani