NestJS Overview

リン (linh)
Goalist Blog
Published in
7 min readMar 4, 2022

I. What is it
It’s a progressive Node.js framework for building efficient, reliable and scalable server-side applications.

So where the hype comes from? Why can i just use ExpressJS? Here’s why:
- Inherits all the pros of ExpressJS because it was built up on Express.js
- Enforce a clear project structure
- Embraces Typescript, Dependency Injection, and Modularity

If you’ve ever used Angular or Springboots, you might see some similarities.

II. Overview

1. Installation

$ npm i -g @nestjs/cli
$ nest new project-name

Use these command lines to install a Nest project.
After installed, you can see that project has a default structure and pre-installed library like jest (for testing) or typescript (for type checking).

project structure

Although there’re options for accepting non-typescript files in nest-cli.json, I personally think that there is no point of using NestJS if you do that.
- main.ts : this is where Nest bootstrap your app.
- app.module.ts : as mentioned earlier, NestJS imbraces modularity, which means that our application is a combination of separate modules. All module should be added in this app module for the app to know what modules included in the application.
- controller.ts : is where you handle your http requests, where you return response to those request
- service.ts : is a kind of providers.

Providers are a fundamental concept in Nest. Many of the basic Nest classes may be treated as a provider — services, repositories, factories, helpers, and so on. The main idea of a provider is that it can be injected as dependency; 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.

CRUD generator : is a simple way to create new resources

nest g resource

This command not only generates all the NestJS building blocks (module, service, controller classes) but also an entity class (this represent a data table, Ex: entity class User represent User table, class properties would be firstName, lastName, age, …), DTO classes (where you define types and condition, if any, for request and response object) as well as the testing (.spec) files.

Ex: I would like to create enpoint for Product entity, type nest g resource products to create a folder dedicate to /products endpoint.

Decorator and Pipe : you will see that decorator and pipe are used throughout the app and they play an important role in making it easy to use Nestjs. There’re not only built-in decorators and pipes but you can also create customs decorators and pipes that suit you.
If you’re not familiar with decorator and pipe concept, i suggest to take a look at below to get a general idea.
pipe : https://morioh.com/p/3cdedeb17367
decorator : https://saul-mirone.github.io/a-complete-guide-to-typescript-decorator/

2. Create an API

When you create an API with Nestjs, here’s what you should look into:

  • Database

Nest allows you to easily intergrate with SQL or noSQL database. Beside the traditional way of connecting and handling database, Nest has tight intergration with TypeORM, Sequelize, Mongoose for additional features such as model/repository injection, testability, and asynchronous configuration to make accessing your chosen database even easier.

Choose the ORM of your favorite and install it.
Then import and configurate it in app.module.ts.
Below is an example of using TypeORM and mySQL:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [],
synchronize: true,
}),
],
})
export class AppModule {}

or, you can create an ormconfig.json file and leave the forRoot() empty

{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "root",
"database": "test",
"entities": ["dist/**/*.entity{.ts,.js}"],
"synchronize": true
}

Once this is done, the TypeORM Connection and EntityManager objects will be available to inject across the entire project (without needing to import any modules) and you can start using ORM syntax to query data.

One thing to keep in mind is that to be able to use ORM, you need to have entity/model/both (depends on ORM you choose), each represents a data table in your database.

Details integration can be found here:
https://docs.nestjs.com/techniques/database

  • Controller

Controllers are responsible for handling incoming requests and returning responses to the client.

To create a controller, simply add @Controller() above the controller class you’re about to create.

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}

@Header('Content-Type', 'text/html')
@HttpCode(204)
@Get(':id')
findOne(@Param() params) {
console.log(params.id);
return `This action returns a #${params.id} cat`;
}
}

Inside the bracket of controller decorator is the API route that the controller is dedicated to.
Ex: @Controller() handle all requests for your-domain/, @Controller(products) handle all requests for your-domain/products

There’re decorators represent the CRUD acions (@Get(), @Post(), @Patch(), @Delete()) to define what function handle what kind of http request and other decorator to handle other things like: header, respond code, etc… And, inside the parameters of function that return response, there’re decorators to access params, queries or request body.

Below is the controller that is created for you, if you use CRUD generator.

  • Providers
    are injectable class that allow to share logic throughout entire app. Any class that has decorator @Injectable can be injected in the constructor of other class.

Service: is a provider. You’re not obliged to use, you can just handle and return the response right at controller. However, the idea is to keep all the things that you want to do with the response, either light or heavy logic, in the service and controller only has to return response.

Below is the service that is created for you, if you use CRUD generator

Guard: is another provider that can be use to handle authentication.
https://docs.nestjs.com/security/authentication#jwt-functionality

Pipe: is a provider that can be injected to controller to validate and transform a value in controller. Beside built-in pipes, you can create your own pipe to transform data as you wish.

Pipes have two typical use cases:
-
transformation: transform input data to the desired form (e.g., from string to integer)
- validation: evaluate input data and if valid, simply pass it through unchanged; otherwise, throw an exception when the data is incorrect

  • Module

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.

So, remember to import individual modules in your root module so that the app knows what to run.
Every module is automatically a shared module. Once created it can be reused by any module, as long as you import it in the other module that you wan to use.

Each module will have an object of properties to describe it:
- providers : are any injectable classes that will be used in this module
- controllers : the set of controllers defined in this module which have to be instantiated
- imports : if you want to use any injectable classes of another modules, list those modules in imports array, and you can use the logics without having to write them again.
- exports : in other for provider of a module to be imported in other modules, you need to export it.

III. Conclusion

Reading the doc might be a bit overwhelming at first.
Although it seems complicated, nestjs is actually easy to start with, if you want to start creating an app, just install it, connect database, add controller to return response, add service to handle respose before return (if you want to), then if you need authorization, add a guard, which is actually well written in the doc, just modify it as you need and you’re good to go. And you don’t have to worry about scaling the app later, if you don’t need to scale it, leave it as is, but if you want to scale it, everything is in structure, ready for you.

--

--

リン (linh)
Goalist Blog

A career-changed-non-tech-background point of view.