TypeScript-based REST API Framework - NestJS

Introduction

 
Nowadays, web applications are being designed with REST API and front-end. For developing a UI application, now, we have so many popular JavaScript frameworks available, like Angular, React, Vue, and many more. For developing REST API, we have multiple options too.
 
If we select Java as a programming language, we have Spring boot; for .NET, we have REST API Framework; if we choose JavaScript, then we have ExpressJS, HapiJS, and NestJS etc. Here, I will walk you through Nest.js (https://docs.nestjs.com/). We will learn to build a web application using TypeScript for REST API.
 

Environment setup

 
First, install the Nest.js CLI on your local machine using the command:
 
npm i -g @nestjs/cli
 
Create a new application.
 
nest new <project-name>
 
After this command, it will ask for some basic information, like description, author, and version. Then only the installation gets started.
 
Typescript Based REST API Framework - NestJS
 
The installation will take 3-5 minutes typically to complete.
 
Typescript Based REST API Framework - NestJS
 
cd sample-nestjs-app and npm run start
 
Using this command, we can easily start the application.
 
Typescript Based REST API Framework - NestJS
 
This application is running on default port 3000.
 
Typescript Based REST API Framework - NestJS
 

Understanding Nest.js

 
Now, let us try to understand what are the different files available and what is the application execution flow NestJS. For this purpose, we have to open the application in an IDE, like Visual Studio Code or Atom.
 
Typescript Based REST API Framework - NestJS
 
The above image is showing the list of files and folders in our Nest.js application. We will go through these one-by-one.
 
Package.json
 
Those who are aware of any node.js based application are already aware of the use of the package.json file. Here, we will try to understand the packages and commands related to NestJS.
  1. "dependencies": {    
  2.    "@nestjs/common""^5.4.0",    
  3.    "@nestjs/core""^5.4.0",    
  4.    "reflect-metadata""^0.1.12",    
  5.    "rimraf""^2.6.2",    
  6.    "rxjs""^6.2.2",    
  7.    "typescript""^3.0.1"    
  8.  }   
nestjs/common and nestjs/core are basically for NestJS dependencies.
 
RxJS is a library for reactive programming used for Observables, to make it easier for composing asynchronous or callback-based code.
 
TypeScript mainly is required as NestJS builds a TypeScript based application.
  1. "scripts": {    
  2.    "build""tsc -p tsconfig.build.json",    
  3.    "format""prettier --write \"src/**/*.ts\"",    
  4.    "start""ts-node -r tsconfig-paths/register src/main.ts",    
  5.    "start:dev""nodemon",    
  6.    "start:debug""nodemon --config nodemon-debug.json",    
  7.    "prestart:prod""rimraf dist && npm run build",    
  8.    "start:prod""node dist/main.js",    
  9.    "lint""tslint -p tsconfig.json -c tslint.json",    
  10.    "test""jest",    
  11.    "test:watch""jest --watch",    
  12.    "test:cov""jest --coverage",    
  13.    "test:debug""node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",    
  14.    "test:e2e""jest --config ./test/jest-e2e.json"    
  15.  }   
These scripts are optional to run multiple options like run the application, build the application, run the unit tests, or run the e2e test cases.
 
tsconfig.json is mainly used for TypeScript compilation into JavaScript.
 
Those not having an understanding of TypeScript must first go through https://www.typescriptlang.org/. Here, you will get detailed information about TypeScript.
 
nodemon.json
  1. {    
  2. "watch": ["src"],    
  3. "ext""ts",    
  4. "ignore": ["src/**/*.spec.ts"],    
  5. "exec""ts-node -r tsconfig-paths/register src/main.ts"   
Nodemon is a utility that will monitor the changes, if any, in your source and automatically restart your server.
 
Exec command calling main.ts
 

src folder

 
Typescript Based REST API Framework - NestJS
 
We have so many files available inside the src folder. This is a very important part of our application.
 
Main.ts
  1. import { NestFactory } from '@nestjs/core';    
  2. import { AppModule } from './app.module';    
  3.     
  4. async function bootstrap() {    
  5.  const app = await NestFactory.create(AppModule);    
  6.  await app.listen(3000);    
  7. }    
  8. bootstrap();   
Here, bootstrap method contains 2 lines only.
  1. First line : const app = await NestFactory.create(AppModule);   
NestFactory.create needs to pass the AppModule.
  1. Second line : await app.listen(3000);   
Here, 3000 is the port number. In case one needs to change the application port, then change 3000 to any other port number.
 
app.module.ts
  1. import { Module } from '@nestjs/common';    
  2. import { AppController } from './app.controller';    
  3. import { AppService } from './app.service';    
  4.     
  5. @Module({    
  6.  imports: [],    
  7.  controllers: [AppController],    
  8.  providers: [AppService],    
  9. })    
  10. export class AppModule {}   
app.module is having three main components.
  • Imports
    This is mainly having an array of all imported modules that need to get specified.
     
  • controllers
    Here, we need to add all controllers (We will have more information about controllers and services below).
     
  • Providers
    It is an array of services that need to be specified.
app.controller.ts
  1. import { Controller, Get } from '@nestjs/common';    
  2. import { AppService } from './app.service';    
  3.     
  4. @Controller()    
  5. export class AppController {    
  6.  constructor(private readonly appService: AppService) {}    
  7.     
  8.  @Get()    
  9.  getHello(): string {    
  10.    return this.appService.getHello();    
  11.  }    
  12. }   
The controller is the main component that exposes all methods to the external world -  like GET, POST, PUT, and Delete.
 
But we need to specify the actual logic in a service which we are importing in our controller and call the expected function. The service is injected in the constructor.
  1. constructor(private readonly appService: AppService) {}   
App.service.ts
  1. import { Injectable } from '@nestjs/common';    
  2.     
  3. @Injectable()    
  4. export class AppService {    
  5.  getHello(): string {    
  6.    return 'Hello World!';    
  7.  }    
  8. }   
Service class is where the actual functionality/validation or database call is specified.
  1. getHello(): string {    
  2.    return 'Hello World!';    
  3.  }   
This is a simple method which is returning a text value. But you can write any kind of complex logic and return the object as per your requirement.
 

CLI Commands

 
A list of available architecture components.
  • class (alias: cl)
  • controller (alias: co)
  • decorator (alias: d)
  • exception (alias: e)
  • filter (alias: f)
  • gateway (alias: ga)
  • guard (alias: gu)
  • interceptor (alias: i)
  • middleware (alias: mi)
  • module (alias: mo)
  • pipe (alias: pi)
  • provider (alias: pr)
  • service (alias: s)
nest generate service users or nest g s users
nest generate class employee or nest g c employee
 
This way we can directly create required components in our application
 

Testing

 
We can have both testing options available - Unit testing and e2e testing.
 
app.controller.spec.ts
 
This is a sample test class created. This includes unit test cases for app.controller and app.service.
  1. import { Test, TestingModule } from '@nestjs/testing';    
  2. import { AppController } from './app.controller';    
  3. import { AppService } from './app.service';    
  4.     
  5. describe('AppController', () => {    
  6.  let appController: AppController;    
  7.     
  8.  beforeEach(async () => {    
  9.    const app: TestingModule = await Test.createTestingModule({    
  10.      controllers: [AppController],    
  11.      providers: [AppService],    
  12.    }).compile();    
  13.     
  14.    appController = app.get<AppController>(AppController);    
  15.  });    
  16.     
  17.  describe('root', () => {    
  18.    it('should return "Hello World!"', () => {    
  19.      expect(appController.getHello()).toBe('Hello World!');    
  20.    });    
  21.  });    
  22. });   
This is a jest test case. We can write multiple test cases as per the functionality and run the unit test cases, npm test. For this purpose, the jest framework is used.
 
For the e2e test, a separate test folder gets created and app.e2e-spec.ts is its sample file.
  1. import { Test, TestingModule } from '@nestjs/testing';    
  2. import * as request from 'supertest';    
  3. import { AppModule } from './../src/app.module';    
  4.     
  5. describe('AppController (e2e)', () => {    
  6.  let app;    
  7.     
  8.  beforeEach(async () => {    
  9.    const moduleFixture: TestingModule = await Test.createTestingModule({    
  10.      imports: [AppModule],    
  11.    }).compile();    
  12.     
  13.    app = moduleFixture.createNestApplication();    
  14.    await app.init();    
  15.  });    
  16.     
  17.  it('/ (GET)', () => {    
  18.    return request(app.getHttpServer())    
  19.      .get('/')    
  20.      .expect(200)    
  21.      .expect('Hello World!');    
  22.  });    
  23. });   
To run e2e tests, the command is
 
npm run test:e2e
 

Summary

 
In this article, we learned some basics of NestJS. When we are talking about NestJS, there are some advanced concepts involved too, like Middleware, Exception, Filters, Pipes, Guards, and Interceptors. Follow my upcoming article on these advanced topics.
 
I have uploaded the code on GitHub also.