Introduction to Nest.js

Introduction to Nest.js

What is Nest.js?

Nest.js is a Node.js framework for creating server-side applications. It uses modular architecture, which means that the application is divided into modules, where each module groups related functionality, so that new functionalities can be easily added without disrupting the existing parts of the application.

Nest.js uses the TypeScript language (although JavaScript can also be used), with the use of decorators (decorators are special tags that are added above the code with which we define additional instructions). In addition to HTTP, Nest.js supports WebSockets, GraphQL, gRPC and other protocols.

nest.js

Modules

In Nest.js, modules are the basic building blocks of an application and serve to organize and structure the code. They group related components such as controllers, providers (services), repositories, and other modules into logical units. Modules are defined using the @Module() decorator.

Module fields:
  • imports: List of modules imported into the current module. These modules are available within modules.
  • controllers: List of controllers defined in the module. Controllers are responsible for handling HTTP requests.
  • providers: List of providers (services) defined in the module. Providers perform business logic and can be injected into controllers or other providers.
  • exports: List of providers that are exported from the module and can be used in other modules.

Creating modules

Using the Nest CLI, you can quickly and easily create modules in your Nest.js application. To create a new module, you can use the nest generate (or nest g for short) command. For example, to create a module called cats, use the following command:

This command will generate a new cats.module.ts file in the src/cats directory, which looks like this:

Example Module

Here’s how to define a simple module in Nest.js:

Main Module (App Module)

Every Nest.js application has a main module, usually named AppModule, which is the root module of the application. It can import other modules and serves as an entry point for the application.

Controllers

Controllers are responsible for handling HTTP requests and returning appropriate responses to clients. In Nest.js, controllers act as intermediaries between the client and the service. They define routes and methods that are fired when certain routes are hit. Controllers are marked with the @Controller() decorator. Decorators are also used within the controller itself to mark specific methods or routes such as: @Get(), @Post(), @Put(), @Delete(), etc.

In this example, CatsController has a single route that responds to GET requests to /cats and returns the string ‘This action returns all cats’.

Adding a controller to a module

After creating a controller or service, you need to update the module to include them:

Example

Services

Services represent the application layer that performs business logic and provides data to controllers. Services usually contain methods that are used to perform various tasks such as accessing a database, working with third-party APIs, processing data, etc.

  • Defining services: Services are defined as classes and typically use the @Injectable() decorator so that Nest.js can inject them into controllers or otherservices.
  • Dependency injection: Services can be injected into controllers or other services using a constructor.

Creating services

To add a new service, use the nest generate service (or nest g service for short) command.

This command will generate a cats.service.ts file in the src/cats directory with the base implementation of the service:

Adding services to the module

When you create a new service using the nest generate service cats command, the Nest CLI will automatically update the corresponding module to include the newly created service in the providers field of that module. This allows the service to be available within the module without additional manual intervention.

Example:

In this example, UsersService has a method findAll that returns a list of users.

Middleware

Middleware are functions that are executed during HTTP request processing. Middleware operates in the space between receiving a request and returning a response, allowing modification of the request and response, redirecting the flow, or terminating the request. In Nest.js, middleware is defined as classes that implement the NestMiddleware interface or as plain functions. Middleware can be applied to specific routes or globally to all routes.

Creating middleware

To add new middleware, use the nest generate middleware (or nest g middleware for short) command.

This command will generate a logger.middleware.ts file in the src directory with the base middleware implementation:

In this example, LoggerMiddleware logs every request that goes through the application.

Registering middleware in the module:

To register the middleware, you need to add it to the appropriate module.

In this example, LoggerMiddleware will be applied to all requests going to the /users route.

Providers

Nest.js has a built-in dependency injection mechanism, which facilitates dependency management and code testing. This means that components such as services can be automatically injected where they are needed, instead of explicitly instantiating them. Read more about dependency injection in the article “What is Dependency Injection”.

Providers are a core concept in Nest.js that enable the creation and sharing of object instances. They are usually used to implement services, but they can also include any class that you want to be available through the Dependency Injection (DI) mechanism ie. providers can be services, repositories, factory functions, etc.

Provider tracking

Providers are marked as classes that use the @Injectable() decorator.

Example

In this example, CatsService is a provider defined with the @Injectable() decorator.

Provider registration

In this example, CatsService is registered as a provider in CatsModule.

Provider injection

Providers can be injected into other classes or providers using a constructor.

Example

Repository

Repositories are a layer that enables data access and management. They abstract the interaction with the database or any other data source, thus allowing for cleaner and more consistent code. They are used to perform CRUD operations (create, read, update, delete).

Example

In this example, the UserRepository uses a TypeORM repository to interact with the User entity.

Exception Filters

Exception filters are like safety nets in a program that catch errors and decide what to do with them. When something unexpected happens in the application, exception filters allow errors to be caught and an appropriate message returned to the user. Exception filters allow us to handle errors centrally and eliminate the need to write actions that would handle errors all over the code.

Step 1: Defining the Exception Filter

We define the filter using the @Catch() decorator. This is a simple example of a filter that catches all errors:

Step 2: Using the Exception Filter

We can apply the filter at different levels: globally (for the entire application), at the controller level or at the level of individual routes.

Application at the Global Level

To make the filter work for the whole application, we will add it to the main file of the application (eg main.ts):

Application at the Controller Level

To make the filter work only for a specific controller, we add the @UseFilters decorator above the controller:

Application at the Level of Individual Routes

To make the filter work only for a specific route, we add the @UseFilters decorator above that route:

Pipes

Pipes in Nest.js are a powerful tool that enables data transformation and validation. Pipes can transform incoming data, verify it, and even discard invalid data. This allows the transformation and validation logic to be centralized and easily reused.

Creating Pipes

A pipe is created by implementing the PipeTransform interface and defining a transform method that will process the data.

Example

In this example a pipe that converts the incoming string to a number:

Using Pipes

You can deploy Pipes at the global level, the controller level, or the route level.

Global Application

Global implementation of pipes is used in the main application file (eg main.ts):

Application on Controller

You can apply pipes to a specific controller using the @UsePipes() decorator:

Application to Route

You can apply pipes to a specific route: