My Experiments with NestJS

Tags: javascript, mongodb, postgres
Published: 2021-07-08 14:05:09


Originally published at [My Experiments with NestJs Medium Blog](https://abhirampai1999.medium.com/my-experiments-with-nestjs-3f2cde4619ba),

During the lockdown, I was persistently trying to be as much productive as possible. That is the time when I came across an open-source disaster management platform Coronasafe Network. There was a project called Stay that was to be implemented for the organization. I and a few of my friends came together to build this platform. The technology stack was ReactJS, NestJS, and Database was Postgres. First, we divided the team into frontend and backend developers, and I was part of the backend team. That is where I first came across the framework NestJS. It is a progressive nodejs framework. Nest provides an out-of-the-box application architecture that allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications. The architecture is heavily inspired by Angular.
## Lets explore more on NestJS
### Installation
```npm i -g @nestjs/cli```
This would install NestJS cli globally in our computer.
Now we can start a new project using the command,
```nest new project-name```
This command would create a new NestJS project with the desired project name we want.
```? Which package manager would you ❤️ to use?
npm
yarn```
I selected npm you can select your desired package manager.

<img src="https://miro.medium.com/max/381/1*aRO1JtEZ9Ll9fy693Kq3HQ.png"/>

After completion of the command we would get such a folder structure.

src would have the following files,

<img src="https://miro.medium.com/max/309/1*qVT1T3vlnuOdIGTbrVimUw.png"/>

App module is the main module of any nestJS application.

Lets see each file in detail,

First lets go for the app.controller.spec.ts,

<img src="https://miro.medium.com/max/813/1*sgcX2SEcWj74jGsxGxMRZQ.png"/>

This is a testing file for the app controller file. It tests whether the controller is working properly.

The next file is app.controller.ts,

<img src="https://miro.medium.com/max/813/1*sgcX2SEcWj74jGsxGxMRZQ.png"/>
 
> Controllers are responsible for handling incoming requests and returning responses to the client.

In this file we define the get, post, put, patch, delete request routes using different decorators defined in the @nestjs/common library.

The constructor of AppController class calls a private readonly object of the AppService class so that the functions defined in the AppService class is accessible within the AppController class. In this case getHello() of appService Class is available to AppController class through the private readonly object appService.

Now lets look at app.service.ts file,

<img src="https://miro.medium.com/max/559/1*sBO8iIqv6ReT41rt3j_d5g.png"/>

Service files are responsible for data storage and retrieval. Here in this file the getHello function called in app.controller.ts file is defined. Service files are decorated with @Injectable() decorator. This says nestJS that the class is nestJS provider.

> The main idea of a provider is that it can inject dependencies; this means objects can create various relationships with each other, and the function of “wiring up” instances of objects can largely be delegated to the Nest runtime system.

Next lets see app.module.ts,

<img src= "https://miro.medium.com/max/660/1*Fl6g8H46ZsS57eiyfl0wxQ.png"/>

>A module is a class annotated with a @Module() decorator. The @Module() decorator provides metadata that Nest makes use of to organize the application structure.

In app.module.ts file we import various modules in our nestJS application. Also we can connect to the databases through app.module.ts file.

### Connection with MongoDB

To connect to a database we need to first install a package @nestjs/typeorm.
```npm i --save @nestjs/typeorm typeorm```

> Nest uses TypeORM because it’s the most mature Object Relational Mapper (ORM) available for TypeScript. Since it’s written in TypeScript, it integrates well with the Nest framework.

```
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
require('dotenv').config();
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mongodb',
      url:
      process.env.MONGOURL,
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      ssl: true,
      synchronize: true,
      logging: true,
      useUnifiedTopology: true,
      useNewUrlParser: true,
    }),
    ],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
```
Here the code above is an example for connecting nestJS application with a mongo database. TypeOrmModule is initialized with type mongodb, the url of the mongo cluster is provided in as an environment variable then entities are the classes where the table structure is defined, for eg:-
```
import {
  Column,
  CreateDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  Unique,
} from 'typeorm';



@Entity('users')
@Unique(['email'])
export class User {

  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 128 })
  name: string;

  @Column({ length: 128 })
  email: string;

  @Column({ length: 128 })
  password: string;

  @Column({ length:128 })
  type: string;

  @Column({ length: 128 })
  status: string;

  @Column({ nullable: true })
  referal: string;

  @Column({nullable: true})
  resetToken: string;

  @Column({ nullable: true })
  lastLogin: Date;

  @CreateDateColumn()
  createdAt: Date;

  @CreateDateColumn()
  updatedAt: Date;


}
```

This is an entity file for the class user or in other words this file describes the model of the user table.

### Connection with Postgres

For connecting with postgres, we first create a DbConfig file that exports a constant DbConfig of type TypeOrmModuleOptions,

```
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as config from 'config';

const dbConfig = config.get('db');


export const DbConfig: TypeOrmModuleOptions = {
  type: 'postgres',
  url: process.env.DATABASE_URL,//provide the database url
  host: dbConfig.host, //provide the host
  port: dbConfig.port , //provide the port number
  username: dbConfig.username, //provide the dbusername
  password: dbConfig.password , //provide the dbpassword
  database: dbConfig.database , //provide the databasename
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  migrations: [__dirname + '/../**/migrations/*{.ts,.js}'],
  synchronize: false,
  migrationsRun: true,
  cli: {
    migrationsDir: 'migrations',
  },
};
```

Then the app.module.ts would be like ,

```
import { Module } from '@nestjs/common';
import {DbConfig} from './config/db.config'
import {TypeOrmModule} from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
  imports: [
    TypeOrmModule.forRoot(DbConfig),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

I have saved the db.config file inside config folder in src. Hence it is being imported from there. Now since we have completed the connection with postgres we have one more thing to look at since postgres is an sql database. We need to run migrations to add the tables in postgres database. For that first we need to create a migration folder and using cmd navigate into the migration folder and run the command

```
npm i -g typeorm

typeorm migration:create -n filename
```

This would create a migration file in the migration folder we created. An example file is,

```
import { MigrationInterface, QueryRunner, Table } from 'typeorm';

export class CreateUser1234567891012 implements MigrationInterface {

  public async up(queryRunner: QueryRunner): Promise<any> {
    return await queryRunner.createTable(new Table({
      name: 'users',
      columns: [
        {
          name: 'id',
          type: 'bigint',
          isPrimary: true,
          isGenerated: true,
          generationStrategy: 'increment',
        },
        {
          name: 'name',
          type: 'varchar',
        },
        {
          name: 'email',
          isUnique: true,
          type: 'varchar',
        },
        {
          name: 'referal',
          type:'varchar',
          isUnique: true,
          isNullable: true,
        },
        {
          name: 'resetToken',
          type:'varchar',
          isUnique: true,
          isNullable: true,
        },
        {
          name: 'type',
          type:'varchar'
        },
        {
          name: 'password',
          type: 'varchar',
          isNullable: false,
        },
        {
          name: 'status',
          type: 'varchar',
          default: '\'ACTIVE\'',
        },
        {
          name: 'lastLogin',
          type: 'timestamp',
          isNullable: true,
          default: 'CURRENT_TIMESTAMP',
        },
        {

          name: 'createdAt',
          type: 'timestamp',
          default: 'CURRENT_TIMESTAMP',
          isNullable: false,
        },
        {

          name: 'updatedAt',
          type: 'timestamp',
          default: 'CURRENT_TIMESTAMP',
          isNullable: false,
        },
      ],
    }), true);
  }

  public async down(queryRunner: QueryRunner): Promise<any> {
    await queryRunner.query(`DROP TABLE "users"`);
  }

}
```

Now when we start the nest application using,

> npm run 

migrations will run automatically and the tables will be created in the postgres db. Up function creates the table whereas down function drops the table from the postgres db.

## Conclusion

NestJS has a content rich documentation avaliable, you can refer to that if required. For more reference of nestjs application I am attaching some of my github repos that uses nestjs,

[Backend of the todo(task) management website using nest] (github.com/Pai026/tasks-manager-be)

[CoronaSafe Stay BE NestJS] (github.com/Pai026/stay_be)

[Backend of Delivery application] (github.com/Delivery-System-App/delivery-app-be)

Any queries , Mail me @ abhirampai1999@gmail.com,
or DM at,

[Linkedin](https://www.linkedin.com/in/abhiram-r-pai-bb3288170)

[Twitter] (https://twitter.com/pai_abhiram)