Building a Production-grade Nodejs,GraphQL and TypeScript Server with CI/CD Pipeline - Part 2
Tags: showdev, webdev, graphql
Published: 2020-05-12 12:20:34

---
title: Building a Production-grade Nodejs,GraphQL and TypeScript Server with CI/CD Pipeline - Part 2
published: true
description: This article explains how to write queries and mutation in typescript graphql and how to inject dependancies such as database model into graphql resolvers.
canonical_url: https://cloudnweb.dev/2020/05/nodejs-graphql-typescript-starter-part-2
tags: showdev,webdev,graphql
---

This article explains how to write queries and mutation in typescript graphql and how to inject dependancies such as database model into graphql resolvers.

This is Part 2 of this series. checkout the previous article here,

[Part 1](https://cloudnweb.dev/2020/04/nodejs-graphql-typescript-starter-part-1)

Let's write Query and Mutation for Login and Signup for User Service. this is one of the common and primary api that you might need to develop for your application.

## Query and Mutation

### Login User

In **UserResolver** file, add the following code,

```tsx
@Query((returns) => UserResponse)
  async loginUser(
    @Arg("email") email: string,
    @Arg("password") password: string,
    @Ctx() ctx: any
  ): Promise<UserResponse> {
    const user = await ctx.userModel.findOne({
      email: email,
    });

    if (user) {
      const { err } = await bcrypt.compare(password, user.password);

      if (!!err) {
        return {
          success: false,
          error: "Invalid Credetials",
          data: null,
        };
      } else {
        return {
          success: true,
          error: null,
          data: user,
        };
      }
    } else {
      return {
        success: false,
        error: "User Not Found",
        data: null,
      };
    }
  }
```

On the above code, we are adding a typescript decorator **@Query.** Also, we add it returns of a custom type here. if a particular query returns a string or array. you can define the default type for it such as string,array or integer.

Sometimes, you need a custom type for your response return type. For example, Here i wanted to return three argument on whether API success or not. they are,

`Success` , `Data` and `Error`

Success indicates whether the API is success or not. Data returns the result data. if the api is failed, it will return the error in error variable. 

This is a custom return type. To achieve this, we can create a custom Object Type in **type-graphql** and use it as a return type here.

create a file **UserResponse.ts** and add the following code,

```tsx
import { Field, ObjectType } from "type-graphql";
import UserSchema from "./UserSchema";
@ObjectType({ description: "User Response" })
export default class UserResponse {
  @Field(() => Boolean)
  success: boolean;

  @Field(() => UserSchema)
  data: UserSchema | null;

  @Field(() => String)
  error: String | null;
}
```

After that, we define the arguments and context inside the login query. 

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

```tsx
async loginUser(
    @Arg("email") email: string,
    @Arg("password") password: string,
    @Ctx() ctx: any
  ): Promise<UserResponse> { }
```

Here, we have arguments `email` and `password` which is of types string. Also, we define the context which will see in later part of this article.

Inside the login resolver, we check whether email is already exists, if it exists. we check the password and return the user data.

### Signup Mutation

In UserResolver, add the following code

```tsx
@Mutation(() => UserSchema)
  async registerUser(
    @Arg("name") name: string,
    @Arg("email") email: string,
    @Arg("password") password: string,
    @Ctx() ctx: any
  ): Promise<IUser> {
    const hashedPassword = await bcrypt.hash(password, 12);

    const user = await new ctx.userModel({
      name,
      email,
      password: hashedPassword,
    });

    return user.save();
  }
```

it will follow the same pattern as login query. only difference is logic inside the function. it creates the hash password and store it in DB.

## Dependancy Injection

dependancy injection is a powerful pattern that helps to decouple your application from the business logics. 

Let me explain with an example here,

```tsx
import UserModel from './userModel'

export class UserResolver {
  
  @Mutation()
  async insertData(){
     const data = UserModel.insertMany(data);
     return {
				success : true,
				data : data,
				error : null
  }
}
```

In the above example, we import the database model directly in our resolver. There is a downside of doing in that way. let's we are using mongoose as our database. what if you want to change your DB to something else. there you have dependancy inside your business logic.

we can avoid this kind of problem using **dependancy injection.** there are two ways to achieve dependancy injection in graphql server.

### DI using GraphQL Context

First way is using graphql context for dependancy injection in our resolver. pass the mongoose model inside the graphql context.

```tsx
 import UserModel from './UserModel'
const server = new ApolloServer({
        schema,
        context: () => ({
          userModel: UserModel,
        }),
      });
```

Now, you can use your mongoose model inside the graphql resolvers from context.

```tsx
 async loginUser(
    @Arg("email") email: string,
    @Arg("password") password: string,
    @Ctx() ctx: any
  ): Promise<UserResponse> {
    const user = await ctx.userModel.findOne({
      email: email,
    });
}
```

In this simple way, you can make your resolver testable and decoupled from third party dependancies.

### DI using Container

Type GraphQL provides a way for DI using container with [typedi](https://www.npmjs.com/package/typedi). In **server.ts**

```tsx
import UserModel from "./UserService/UserModel";
import { UserResolver } from "./UserService/UserResolver";
import * as Mongoose from "mongoose";
import { Container } from "typedi";

Container.set({ id: "USER", factory: () => UserModel });

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

Here, we set our User Mongoose model inside the container. After that, create a **UserService.ts** which handles the mongo operations

```tsx
import { Service, Inject } from "typedi";
import { IUserModel, IUser } from "./UserModel";

@Service()
export class UserService {
  constructor(@Inject("USER") private readonly user: IUserModel) {}

  async getAll() {
    return this.user.find();
  }

  async getById(id: string): Promise<IUser | null> {
    return this.user.findOne({ _id: id });
  }

  async getByEmail(email: string): Promise<IUser | null> {
    return this.user.findOne({ email }).exec();
  }

  async insertUser(userInfo: any): Promise<IUser> {
    const user = new this.user(userInfo);
    return user.save();
  }
}
```

User Service is decorated with **@Service** and user model is inject into it. For every db operations such as 

- getAll
- getById
- getByEmail
- insertUser

we create a function and wrap the Mongodb operation inside it. After that, import the Service inside the resolver constructor and access it using

`this.userService.getAll`

```tsx
constructor(private readonly userService: UserService) {}

@Mutation(() => UserSchema)
  async registerUser(
    @Arg("name") name: string,
    @Arg("email") email: string,
    @Arg("password") password: string,
    @Ctx() ctx: any
  ): Promise<IUser> {
    const hashedPassword = await bcrypt.hash(password, 12);

    const user = await this.userService.insertUser({
      name,
      email,
      password: hashedPassword,
    });

    return user;
  }
```

Complete Source [code](https://github.com/ganeshmani/graphql-typescript-server-starter/tree/dependancy-injection)

### Conclusion

this article covers how to write queries and mutation in typescript graphql server and how to inject dependancy in the graphql resolvers.

In upcoming article, we will see how to write test cases for your application and automate the deployment process of your application server. 

Until then,Happy coding :-)