Introduction to NestJS Part 1

COMET
7 min readJul 1, 2021

--

Introduction

At 5mart Studio we use Javascript for most of our projects. At the same time, we shouldn’t forget about the fact that Javascript is not a high-level programming language, which implies we can easily run into errors that we would never experience while using a high-level programming language. In order to correct or to find the root cause of these errors people usually need to put tremendous hours in. Our solution to correct these errors is definitely Typescript. Although many would bet on the combination of Javascript + Flow just to spare some time, and to avoid errors, we would still choose Typescript. When we started using Typescript we could easily discover its advantages, its reliability and the sheer fact that in the long run we would just definitely benefit from using it for programming. That’s the reason we started thinking about not only using Typescript in React but also switching from the Spring Boot framework on the backend to Typescript. Long story short, that’s how we found the NestJS framework.

What is NestJS?

NestJS is a NodeJS framework entirely composed in Typsecript, which we could now use on an ExpressJS basis that is acknowledged by many great companies, or on a quite newby but still promising and faster Fastify basis. The framework tends to smartly build CLI, DI (Dependency Injection), Modular architecture, GraphQL / REST support, Microservice architecture and supports many database connections such as Postgres(SQL) or Mongo(NoSQL)

At 5mart Studio we always choose the accessories we want to use with NestJS depending on whether we develop for a client or an internal project for ourselves. If we develop for a client we always use well acquainted technologies, e.g. an Express based Postgres database. When it comes to own projects, we like to experiment and learn with new frameworks such as Fastify.

Why NestJS?

NestJS truly gives us a unique opportunity regardless of the size of our project. When we are ahead of a tiny or medium project we can create a simple REST API with it but still on a secure, certain and scalable basis. At the same time, NestJS even gives a helping hand when it comes to the project of your life, since it supports the Microservice architecture perfectly.

Nevertheless, if someone finds NestJS attractive but do not know about Typescript, still have the opportunity to write the code in Javascript. In that scenario, they lose the advantages provided by Typescript, but won’t lose the ones that come with NestJS such as Dependency Injection that is one of its best and default functions. What is more, It is still possible to build Dependency Injection in for a project that is not dependent on NestJS, for example by using Inversify. It is also true however, that it might result in a lot of boilerplate codes, which NestJS would have reduced in the first place.

Fundamentals

Starting a new project

When it comes to the creation of a project, the first and foremost step is to install Nest CLI. In order to do that, you need to run the following in a Terminal window:

In case you are using npm package manager:

npm install -g @nestjs/cli

Or in case of Yarn:

yarn global add @nestjs/cli

Actually we suggest you use yarn.

After installing CLI you might create the project by giving he following command:

nest new project-name

If you run the command successfully, your project is created in the chosen folder. By opening this particular folder you should enter the following command

yarn start:dev

and you are free to run your project.

In that phase you won’t be able to do much with it, but we are sure everyone have their own favorite libraries they are happy to use, like moment for manipulating time or lodash, a utility library. We won’t really elaborate on these for now, but everyone should just choose their own fav. We frankly have ours.

Fundamentals of NestJS

In a quite recent version, NestJS got a completely new CLI command:

nest generate resource

By using this command you can generate an entire module (we will talk about this later) that contains the controller (or the resolver) that also includes the REST API or GraphQL endpoints. Not to mention the DTOs (Data Transfer Object) with which you can check the content of the requests sent to the endpoints (you should not mix this up with a simple endpoint protection). You can also generate a Service, in which it is possible the compose the logical code bits and even a model where you can give the architecture of the tables in your database. Not but not least, you can even generate the module of the given resource.

Modules of NestJS

A NestJS module is basically a class, which is annotated by the @Module() decorator function.

Every application has its root module like app.module.ts. That module collects all the other modules and gathers them as an entire application. As for the submodules, they are like the users module, where you can find the endpoints and services connected to the user.

Modules in NestJS

The code of a module looks like this:

import { Module } from '@nestjs/common';
import { DogsController } from './dogs.controller';
import { DogsService } from './dogs.service';

@Module({
imports: [],
exports: [DogsService],
controllers: [DogsController],
providers: [DogsService],
})
export class DogsModule {}

As you can see, one single module is responsible for 4 other attributes.

controllers: here you might ad the controllers of a module where the endpoints are located.

providers: all the things you want to share within the given module (like a service for a controller).

imports: all the other modules that can be used within a module.

exports: the parts of the given module that can be available for other modules, for example any of the services found within the module.

Let’s just take two modules, User and Profile as an example. A given service method within the user service has to import a method from the profile service. In that scenario the profile service becomes the dependency of the user service. Therefore you have to export the profile service in the Profile Module while making it available for other modules. Last but not least, in the User Module you have to add the Profile Module among the imports. It is highly important to note that a given module imports another one in most of the case, but does not export itself, only its own services. That’s how the dependency injection is brought to life between to modules. Within the module, the dependency injection is lead by the providers.

import { Module } from '@nestjs/common';
import { DogsModule } from '../dogs/dogs.module';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
imports: [DogsModule], // UsersService can now access the DogsService because the DogsService is exported in the DogsModule, and the DogsModule is imported in the UsersModule.
exports: [UsersService],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

NestJS Controller

Controllers practically work the same as in every other web-based framework. They process the incoming request and give answers based on the evaluation of the requests, even if it is a result or an error.

The controller is also a class annotated by a @Controller() decorator function.

import { Controller, Get } from '@nestjs/common';

@Controller('dogs')
export class DogsController {
@Get()
findAll(): string {
return 'This action returns all dogs';
}
}

The methods of a controller class are placed within a certain controller class. These are also very simple class methods, only annotated by a decorator function.

The 4 decorators needed for a basic REST API:

@Get(): it will mark the method as a GET endpoint.

@Post(): it will mark the method as a POST endpoint.

@Put(): it will mark the method as a PUT endpoint.

@Delete(): it will mark the method as a DELETE endpoint.

If you have already worked with REST API, you probably know what these mean exactly or how to use them.

NestJS Service

A service (provider) is a class that has to be annotated by the @Injectable() decorator function.

As it has already been mentioned earlier, a service can be the dependency of another service, so it should be marked with an @Injectable() decorator so that it can be exported by one module, and imported by another.

There are no such limitations within the services classes as within controllers, e.g. that a class method has to be annotated by a given decorator function. Here are the parts of the business logic and database queries should happen here.

import { Injectable } from '@nestjs/common';
import { Dog } from './interfaces/dog.interface';

@Injectable()
export class DogsService {
private readonly dogs: Dog[] = [];

create(dog: Dog) {
this.dogs.push(dog);
}

findAll(): Dog[] {
return this.dogs;
}
}

Conclusion

In the second part of our post we are going to discover what Guards, Middlewares and Interceptors are and how to use them for a real project.

I truly hope that this short introduction could raise your attention and you just can’t wait to try out NestJS. We at 5mart Studio just simply love it and hope that you and your clients will also benefit from the great features of NestJS in the long run.

--

--

COMET
COMET

Written by COMET

strategy driven digital studio. We help businesses identify, explore and respond to the endless possibilities of the digital space.

No responses yet