Developing REST API Framework using TypeScript and NestJS

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 _

After this command, it will ask for some basic information, like description, author, and version. Then only the installation gets started.

This is image title

The installation will take 3-5 minutes typically to complete.

This is image title

cd sample-nestjs-app and npm run start

Using this command, we can easily start the application.

This is image title

This application is running on default port 3000.

This is image title

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.

This is image title

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.

"dependencies": {  
   "@nestjs/common": "^5.4.0",  
   "@nestjs/core": "^5.4.0",  
   "reflect-metadata": "^0.1.12",  
   "rimraf": "^2.6.2",  
   "rxjs": "^6.2.2",  
   "typescript": "^3.0.1"  
 }  

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.

"scripts": {  
   "build": "tsc -p tsconfig.build.json",  
   "format": "prettier --write \"src/**/*.ts\"",  
   "start": "ts-node -r tsconfig-paths/register src/main.ts",  
   "start:dev": "nodemon",  
   "start:debug": "nodemon --config nodemon-debug.json",  
   "prestart:prod": "rimraf dist && npm run build",  
   "start:prod": "node dist/main.js",  
   "lint": "tslint -p tsconfig.json -c tslint.json",  
   "test": "jest",  
   "test:watch": "jest --watch",  
   "test:cov": "jest --coverage",  
   "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",  
   "test:e2e": "jest --config ./test/jest-e2e.json"  
 }  

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

{  
"watch": ["src"],  
"ext": "ts",  
"ignore": ["src/**/*.spec.ts"],  
"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

This is image title

We have so many files available inside the src folder. This is a very important part of our application.

Main.ts

import { NestFactory } from '@nestjs/core';  
import { AppModule } from './app.module';  
  
async function bootstrap() {  
 const app = await NestFactory.create(AppModule);  
 await app.listen(3000);  
}  
bootstrap();  

Here, bootstrap method contains 2 lines only.

First line : const app = await NestFactory.create(AppModule); 

NestFactory.create needs to pass the AppModule.

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

import { Module } from '@nestjs/common';  
import { AppController } from './app.controller';  
import { AppService } from './app.service';  
  
@Module({  
 imports: [],  
 controllers: [AppController],  
 providers: [AppService],  
})  
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

import { Controller, Get } from '@nestjs/common';  
import { AppService } from './app.service';  
  
@Controller()  
export class AppController {  
 constructor(private readonly appService: AppService) {}  
  
 @Get()  
 getHello(): string {  
   return this.appService.getHello();  
 }  
}  

Controller is the main component which 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.

constructor(private readonly appService: AppService) {}  

App.service.ts

import { Injectable } from '@nestjs/common';  
  
@Injectable()  
export class AppService {  
 getHello(): string {  
   return 'Hello World!';  
 }  
}  

Service class is where the actual functionality/validation or database call is specified.

getHello(): string {  
   return 'Hello World!';  
 }  

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.

import { Test, TestingModule } from '@nestjs/testing';  
import { AppController } from './app.controller';  
import { AppService } from './app.service';  
  
describe('AppController', () => {  
 let appController: AppController;  
  
 beforeEach(async () => {  
   const app: TestingModule = await Test.createTestingModule({  
     controllers: [AppController],  
     providers: [AppService],  
   }).compile();  
  
   appController = app.get<AppController>(AppController);  
 });  
  
 describe('root', () => {  
   it('should return "Hello World!"', () => {  
     expect(appController.getHello()).toBe('Hello World!');  
   });  
 });  
});  

This is a jest test case. We can write multiple test cases as per the functionality and to run the unit test cases, npm test. For this purpose, the jest framework is used.

For e2e test, a separate test folder gets created and app.e2e-spec.ts is its sample file.

import { Test, TestingModule } from '@nestjs/testing';  
import * as request from 'supertest';  
import { AppModule } from './../src/app.module';  
  
describe('AppController (e2e)', () => {  
 let app;  
  
 beforeEach(async () => {  
   const moduleFixture: TestingModule = await Test.createTestingModule({  
     imports: [AppModule],  
   }).compile();  
  
   app = moduleFixture.createNestApplication();  
   await app.init();  
 });  
  
 it('/ (GET)', () => {  
   return request(app.getHttpServer())  
     .get('/')  
     .expect(200)  
     .expect('Hello World!');  
 });  
});  

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.

Thank you !

#typescript #javascript #nestjs #restapi #front-end

Developing REST API Framework using TypeScript and NestJS
27.80 GEEK