Building a Production-grade Nodejs,GraphQL and TypeScript Server with CI/CD Pipeline - Part 1
Tags: typescript, graphql, webdev, showdev
Published: 2020-04-29 06:09:25

---
title: Building a Production-grade Nodejs,GraphQL and TypeScript Server with CI/CD Pipeline - Part 1
published: true
description: This article is the first part of building a production grade nodejs,graphql and typescript server with auto deployment pipeline.
tags: typescript,graphql,webdev,showdev
canonical_url: https://cloudnweb.dev/2020/04/nodejs-graphql-typescript-starter-part-1
conver_image: https://dev-to-uploads.s3.amazonaws.com/i/74icq99q7yojdjm1my0o.png
---

This article is the first part of building a production grade nodejs,graphql and typescript server with auto deployment pipeline.

## Recent articles

- [React Refs with some real world use cases](https://cloudnweb.dev/2020/04/react-refs-with-some-react-world-use-cases)
- [Modern React Redux Tutorials with redux toolkit](https://cloudnweb.dev/2020/04/modern-react-redux-tutotials-redux-toolkit)
- [Building a Piano with React Hooks](https://cloudnweb.dev/2020/02/building-a-piano-with-react-hooks)


there are tons of articles and tutorials are available to explain how to build a scalable backend solutions. but, what i felt missing was a solution that connects all the dots with a simple and proper use-cases.

Most of the time, we won't directly jump into building the application by coding it. we would start with designing how the backend should be based on the application requirement. knowing how to do that is an important skill to have than just knowing the syntax of x or y framework.

### What are we building?

Before coding, let's see what we are going to build to learn the concepts. we will be building a Image management application where users can manage their image resources.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/51ogum200dae0xehs4an.png)

Mainly, it will contain login,signup and main application. In main application, user can upload images and view all the uploaded images. Even though it's a simple use-case, we can understand all the concepts using this simple use-case.

### Screens

**Signup Screen**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/l2wyvah6cpucsefeepe2.png)

**Login Screen**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/l19xo1l8kbkj90bthb2n.png)

**Main App Screen**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/86koci3yy4a1tvlxdxd9.png)

Checkout the Figma file [Here](https://www.figma.com/file/jUiGuUaLa67LFY3flGiQFz/image_management_app?node-id=0%3A1)

Now, we know what application we are going to build. let's apply all the best practices to build a Nodejs,GraphQL and TypeScript Server.

This part is going to explain how to setup the  application and create a query and mutations using GraphQL and TypeScript.

## Setup

we will be using [type-graphql](https://github.com/MichalLytek/type-graphql) for your application. let's install the required dependancies for our application,

 

```bash
npm i apollo-server-express express graphql reflect-metadata type-graphql mongoose
```

- [Apollo-server-express](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-express) - It handles the Apollo graphql and Express connetion. apollo server connects with express for request handling.
- [express](https://github.com/expressjs/express)- expressjs handles the requests in the server
- [graphql](https://graphql.org/) - it is used to handle the graphql schema and resolvers.
- [type-graphql](https://github.com/MichalLytek/type-graphql) - This library is used to manage all the types in graphql.
- [mongoose](https://www.npmjs.com/package/mongoose) - library used to connect with mongodb database

```bash
npm i --save-dev @types/express @types/graphql @types/node nodemon ts-node ts-node-dev typescript  
```

Above dependancies helps us to manage the types and development server daemon for our application.

Now, we need to configure tsconfig file in our application. create a file `tsconfig.json` and add the following,

```json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "lib": [
      "dom",
      "es6",
      "es2017",
      "esnext.asynciterable"
    ],
    "sourceMap": true,
    "outDir": "./dist",
    "moduleResolution": "node",
    "declaration": false,
    "composite": false,
    "removeComments": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "allowSyntheticDefaultImports": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "baseUrl": ".",
    "rootDir": "src"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "./src/**/*.tsx",
    "./src/**/*.ts"
  ]
}
```

create a file **src/server.ts** and add the following code,

```tsx
import { ApolloServer } from "apollo-server-express";
import * as Express from "express";
import "reflect-metadata";
import { buildSchema } from "type-graphql";

import * as Mongoose from "mongoose";
async function startServer() {
  require("dotenv").config(__dirname + ".env");

  const schema = await buildSchema({
    resolvers: [],
    emitSchemaFile: true,
  });

  const app = Express();

  const MONGO_USER = process.env.MONGODB_USER;
  const MONGO_PASS = process.env.MONGODB_PASS;

  Mongoose.connect(
    `mongodb+srv://${MONGO_USER}:${MONGO_PASS}@cluster0-xv4mh.mongodb.net/test?retryWrites=true&w=majority`,
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    }
  )
    .then((res) => {
      console.log("Mongodb is connected successfully");

      const server = new ApolloServer({
        schema,
        context: () => ({
         
        }),
      });

      server.applyMiddleware({ app });
      const PORT = process.env.PORT;
      app.listen(PORT, () => {
        console.log(`server is running on PORT ${PORT}`);
      });
    })
    .catch((err) => {
      console.log(err);
    });
}

startServer();
```

On the above code, we create a async function to bootstrap our application.

```tsx
async function startServer(){

  //Main code comes Here
}

startServer();
```

Inside the function, we build the schema for your application by providing the resolvers. yeah, you read it right.. Graphql schemas are auto generated in type-graphql.

```tsx
 const schema = await buildSchema({
    resolvers: [//our resolvers come here],
    emitSchemaFile: true,
  });
```

After that, we connect with MongoDB Database and start our serve.

```tsx
 Mongoose.connect(
    `mongodb+srv://${MONGO_USER}:${MONGO_PASS}@cluster0-xv4mh.mongodb.net/test?retryWrites=true&w=majority`,
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    }
  )
    .then((res) => {
      console.log("Mongodb is connected successfully");

      const server = new ApolloServer({
        schema,
        context: () => ({
         
        }),
      });

      server.applyMiddleware({ app });
      const PORT = process.env.PORT;
      app.listen(PORT, () => {
        console.log(`server is running on PORT ${PORT}`);
      });
    })
    .catch((err) => {
      console.log(err);
    });
```

**Environment Variable Setup**

we will be using **dotenv** in our application to manage the environment variables for development.

```tsx
  require("dotenv").config(__dirname + ".env");
```

**.env**

```tsx
PORT=5678
MONGODB_USER=root
MONGODB_PASS=Root!23456
```

Now, we got everything to run the basic server in typescript. To run the development typescript server, add the following script in application.

```json
"dev": "ts-node-dev --respawn src/server.ts"
```

you can run your development server using the command,

```bash
npm run dev
```

## DDD for our Application

Let's break our application into domains. so, that we can wrap our business logic based on the domains.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i2rewa72ynzj799k1ifu.png)

Here, we can consider the entities as our feature. we have **User** and **Asset** as an entity. Let's create the file structure based on that,

Let's start with User Service and create all the Queries and Mutations for that service.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e9ztnvpannm0tfmuuci7.png)

## MongoDB and TypeScript

To work with MongoDB and Typescript, let's install few dependancies that are required.

```bash
npm i --save-dev @types/mongoose
```

After that, create a UserModel.ts file in the UserService and add the following code.

```tsx
import * as Mongoose from "mongoose";

export interface IUser extends Mongoose.Document {
  name: String;
  email: String;
  password: String;
}

const UserSchema: Mongoose.Schema = new Mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
    },
    email: {
      type: String,
      required: true,
    },
    password: {
      type: String,
      required: true,
    },
  },
  { timestamps: true }
);

export default Mongoose.model<IUser>("User", UserSchema);
```

On the above code, we define a mongoose schema which returns type mongoose schema along with the fields for User Model.

After that, we define an interface for our User Model,

```tsx
export interface IUser extends Mongoose.Document {
  name: String;
  email: String;
  password: String;
}
```

If you are new to typescript interfaces, checkout this [docs](https://www.typescriptlang.org/docs/handbook/interfaces.html) to know more.

```tsx
export default Mongoose.model<IUser>("User", UserSchema);
```

Finally, we export the mongoose model which implements **IUser** interface. we have successfully create our mongoose model. 

> Note: Here i am using MongoDB as database. if you want to use SQL, checkout this [series](https://www.youtube.com/watch?v=bqdEXPzjzQ4&list=PLN3n1USn4xlma1bBu3Tloe4NyYn9Ko8Gs&index=2) from ben awad

## Resolvers

Every resolver in type-graphql starts with an Resolver  decorator tag with it.

```tsx
@Resolver((of) => UserSchema)
export class UserResolver {
   //Queries and Mutation Comes Here
}
```

Here, we define it is a resolver of a particular Schema. Let's write the schema file for user and continue with resolver function.

**UserSchema.ts**

```tsx
import { Field, ObjectType, ID } from "type-graphql";
import { IsEmail, Length } from "class-validator";

@ObjectType({ description: "User Schema" })
export default class User {
  @Field(() => ID)
  id: String;

  @Field()
  @Length(1, 30)
  name: String;

  @Field()
  @IsEmail()
  @Length(1, 30)
  email: String;

  password: String;
}
```

On the above code, we define it is an Object type with a decorator. For every field, we have a Field decorator. So that, it will reflects in the graphql schema. we can also validate different parameters such as length and email.

If you watch it carefully, we haven't set any decorators for password. if you don't want a value to be in the graphql schema. we have left it out from Field decorator. import the schema in our resolver.

```tsx
import UserSchema from "./UserSchema";
```

Let's write a sample Query and test it out whether our setup is working correctly.

```tsx
@Query(() => String)
  sample(): String {
    return "Hello";
  }
```

Every Query and Mutation starts with Query or Mutation Decorator and it's return type. Here, we have a return type of String.

**UserResolver.ts**

```tsx
import {
  Arg,
  FieldResolver,
  Query,
  Mutation,
  Resolver,
  Ctx,
  Root,
} from "type-graphql";
import UserSchema from "./UserSchema";

@Resolver((of) => UserSchema)
export class UserResolver {
  @Query(() => String)
  sample(): String {
    return "Hello";
  }
}
```

After that, import the resolver in our server file and define it in our schema resolvers

```tsx
import { UserResolver } from "./UserService/UserResolver";

const schema = await buildSchema({
    resolvers: [UserResolver],
    emitSchemaFile: true,
  });
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vf3xqnm9baijhs3alpty.png)

Now, we have a Typescript GraphQL Server running successfully in our machine.

![](https://media.giphy.com/media/102h4wsmCG2s12/giphy.gif)

## Conclusion

I am wrapping up this part here, Let's see how to create 

- Login
- Register
- Authentication
- File Upload

functionalities in upcoming articles. Until then Happy coding