Furthermore, Node.js doesn’t set any structure for applications. This starts with missing type system and ends with the structure directory. Node.js developers are completely free in their application design, which is an almost insurmountable hurdle for newcomers. It is at this point where frameworks, such as Nest.js, come into play.
Nest.js is a framework written in TypeScript, which represents an abstraction layer above the HTTP module of Node.js. There is another abstraction layer between Node.js and Nest.js, which is formed by a web application framework. The framework Express [1] is used here by default. However, Nest.js is designed in such a flexible way that this layer can be exchanged with just a few lines of code. Every abstraction layer adds additional features and interfaces, which make the implementation of applications much easier. TypeScript significantly reduces the initial hurdle for users who are switching from strictly typed languages. At the same time developers can benefit from the advantages of a typed language.
In contrast to Node.js, Nest.js does set specifications regarding the architecture of an application. Nest.js follows the design patterns of the frontend framework Angular very closely. Some examples are the Dependency Injection [2], the work with Decorators [3], or the MV* pattern (you can read up on them as MVC [4], MVVM [5], MVP [6]). Currently, Express is the de facto standard among the frameworks for the development of web applications. But the framework hasn’t been developed any further for several years now. Nest.js is a breath of fresh air for the server-side-development with JavaScript, because it takes modern design patterns from the frontend and implements them server-side.
First steps in Nest.js
One goal, the developers of Nest.js have in mind, is to make it easier for a beginner to start the development of an application. For this purpose, they have taken inspiration from the frontend world and provided an intuitive CLI, with which an application can be initialized with a single command. The nest CLI is installed with the command npm install -g @nestjs/cli.
After the installation, the application is initialised with:
nest new todo-app
todo app
stands here for the project name. At the same time, this name is also used as a directory name. Certain aspects of the application can be configured during the initialisation. The CLI, for example, asks for metadata like description, versioning, author, and lastly which packaging manager shall be used. After the Nest CLI creates the basic structure and all the necessary dependencies have been downloaded, the application can be started in the development operation with the following command:
npm run start:dev
In this case, nodemon is used to automatically restart the process when changes are made so that they take immediate effect. The application can be accessed in the browser via http://localhost:3000 after it has been started.
The structures of a Node.js application
As mentioned, Nest.js sets a number of specifications for the structure of the application. These follow the Angular guidelines. The base application, which is generated by the CLI, contains the three most important building blocks of an application: module, controller and service.
Modules
The module plays, hereby, the role of a container in which the elements for Dependency Injection are registered. The module is introduced by the @Module Decorator, which can be used to define meta-information for the module. The structure of the app module looks like this:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Further modules can be imported with the property imports. With controllers classes are imported that are responsible for certain paths of the application and answer incoming requests. Finally, providers register services that are used to store data and encapsulate the application logic.
A custom module can be added via the CLI with a command. The following command creates a module named todo:
nest generate module todo
Controller
A controller is a TypeScript class that is provided with the @Controller decorater.
The following source code shows an example of a simple Nest.js controller.
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(); } }
Analogue to Angular, the Dependency Injection in Nest.js is implemented as a Constructor Injection [7]. If a variable of the type of a registered service is specified here after the access modifier, the Dependency Injector ensures that an instance of the service is created and passed to the controller class. If a method of the controller is provided with the @Getdecorator, then this means that it is a routing method. In the example, the getHello method is executed when a user calls the URL http://localhost:3000/. The return value of this method is also the response to the user. The example returns the result of the appService.getHello function call. To create, for example, a todo controller, the following command is used:
nest generate controller todo
If a controller has the same name as a module, it is automatically assigned to the module. Otherwise, this assignment can also be achieved by placing the module name before the controller name and separating it with a slash. The assignment also ensures that the controller is automatically entered in the module and can thus be used. In addition to the controller file, a file with the extension .spec.ts is created. This file contains a first unit test for the controller. Tests can be executed in a Nest.js application with the command npm test. By default, the test framework jest is used by Nest.js.
Service
The @Injectable decorator starts a service class. This class can be a data deliverer as well as a logic container in an application.
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string {   return 'Hello World!'; } }
In the example the getHello method only returns the string Hello World!, which is sent to the client. If the return value is changed from Hello World! to Hello Client!, the combination of nodemon and TypeScript compiler automatically restarts the server process. The user then only has to reload the browser window so that the changes also take effect there.
A todo service is added to the project as follows:
nest generate service todo
If the service has the same name as an existing module, the file is created in the directory of the module and the service is registered in the module. The service can then be integrated and used within the module via Dependency Injection.
Similar to the controller, a test file is also created when a service is created.
Conclusion
In contrast to many other Node.js frameworks and libraries, Nest.js uses modern paradigms with which applications can be implemented quickly and efficiently. The distribution of the framework is constantly growing and so is the community that has formed around it. With its open plug-in infrastructure, Nest.js enables a developer to write extensions for the core framework and to easily extend the functionality.
Links & Literature
[1] https://github.com/expressjs/express
[2] https://de.wikipedia.org/wiki/Dependency_Injection
[3] https://www.typescriptlang.org/docs/handbook/decorators.html
[4] https://de.wikipedia.org/wiki/Model_View_Controller
[5] https://de.wikipedia.org/wiki/Model_View_ViewModel
[6] https://de.wikipedia.org/wiki/Model-View-Presenter
[7] https://de.wikipedia.org/wiki/Dependency_Injection#Constructor_Injection
The article is published for the first time in a German version of the blog of MaibornWolff GmbH.