NestJS It is a framework for building efficient, scalable Node.js server-side applications which is completely written in TypeScript (also supports JS), is easily tested and contains everything you need. This framework combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
NestJS provides a level of abstraction above these frameworks, but can also expose their APIs directly to the developer. This allows for easy use of the myriad third-party modules which are available for each platform. You can include them in your project but it not necessary because NestJS provide to you many already included ways to implement your features.
NestJS is a framework designed to make a developer’s life easier, using the right architectural approaches and dictating his own rules.
To start you can create application template by CLI or clone template from GitHub repository.
To create a project you should install on your machine NestJS CLI by next command:
npm i -g @nestjs/cli
And then you can create some project template by:
nest new project-name
Where project-name is the name of your project.
This will create a new project directory, and populate the directory with the initial core Nest files and supporting modules, creating a conventional base structure for your project. Creating a new project with the Nest CLI is recommended for first-time users.
Also, you can download a project template from GitHub repository by:
git clone https://github.com/nestjs/typescript-starter.git project cd project npm install npm run start
In result, you will get similar project templates. main.ts includes an asynchronous function that loading your application.
import { NestFactory } from '@nestjs/core'; import { ApplicationModule } from './modules/app.module'; async function bootstrap() { const app = await NestFactory.create(ApplicationModule); await app.listen(3000); } bootstrap()
Here you can see creating of an instance of the application (app) and providing a module of our application. You can specify a port number for your application.
After running application by npm run start command, you will see that the server has been started by port number 3000.
Controllers
Controllers are responsible for request processing and responses sending back to the client. For example:
import { Controller, Get } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() findAll() { return []; } }
As you see here we use Decorator @Controller() for saying that UsersController this is a controller and his functions should process API requests. We can set URL prefix for all routes, placed in this controller by providing string parameter to decorator @Controller. In the example we set prefix users, so all routes placed in UsersController start with substring /users.
For specifying functions that processed a request for specific URLs we set decorators for UsersControllers functions. In the example, you see that with decorator @Get() helps we processed GET request to URL /users by function findAll().
Also, we can specify URL path by providing to decorator @Get() as parameter some string. For example, we can write @Get(‘active’) and in result, we will get path /users/active for function findAll().
Service, Repository, Factory, Helper, etc are Providers. They can be embedded in controllers and other providers. If you say in Angular, this is all @Injectables
import { Injectable } from '@nestjs/common'; import { User } from './interfaces/user.interface'; @Injectable() export class UsersService { private readonly users: User[] = []; create(user: User) { this.users.push(user); } findAll(): User[] { return this.users; }
Here we can implement some data logic. For example, we can inject here ODM model and work with the database.
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.
Each application has at least one module, a root module. The root module is the starting point Nest uses to build the application. We can imagine an application as a graph. Nest uses to resolve module and provider relationships and dependencies. While very small applications may theoretically have just the root module, this is not the typical case. We want to emphasize that modules are strongly recommended as an effective way to organize your components. Thus, for most applications, the resulting architecture will employ multiple modules (one module for one component of entity of your project, for example).
Middleware is a function which is called before the route handler. Middleware functions have access to the request and response objects, and the next() middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
Middleware functions can perform the following tasks:
You implement custom Nest middleware in either a function or in a class with an @Injectable() decorator. The class should implement the NestMiddleware interface, while the function does not have any special requirements. Let’s start by implementing a simple middleware feature using the class method.
import { Injectable, MiddlewareFunction, NestMiddleware } from '@nestjs/common'; import * as httpProxy from 'http-proxy-middleware'; import { EnvironmentConfigUtils as env } from '../utils/environment-config.utils'; @Injectable() export class GeographyMiddleware implements NestMiddleware { resolve(name: string): MiddlewareFunction { return httpProxy( [ '**', '!/geography/locationsExtendedInfo', ], { logLevel: `${env.string('LOG_LEVEL', 'debug')}`, changeOrigin: true, onProxyReq: (proxyReq, req, res, options) => { const apiKey = env.string('API_KEY', ''); if (apiKey) { proxyReq.setHeader('apiKey', apiKey); } if (req.body) { const bodyData = JSON.stringify(req.body); proxyReq.setHeader('Content-Type', 'application/json'); proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)); proxyReq.write(bodyData); proxyReq.end(); } }, onError(err, req, res) { res.writeHead(500, { 'Content-Type': 'text/plain', }); res.end('Proxy error.'); }, }, ); } }
A pipe is a class annotated with the @Injectable() decorator. Pipes should implement the PipeTransform interface. Pipes process client request before then will be processed in the controller function.
Pipes have two typical use cases:
In both cases, pipes operate on the arguments being processed by a controller route handler. Nest interposes a pipe just before a method is invoked, and the pipe receives the arguments destined for the method. Any transformation or validation operation takes place at that time, after which the route handler is invoked with any (potentially) transformed arguments.
Also, the Nest provides you with two pipes available right out-of-the-box: ValidationPipe and ParseIntPipe. These pipes use in @nestjs/common and you can use it in your application too.
A guard is a class annotated with the @Injectable() decorator. Guards should implement the CanActivate interface.
Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (permissions, roles or other logic what you can implement in guard class) present at run-time. And maybe the best way to use guards this is authorization. Authorization (and its cousin, authentication, with which it usually collaborates) has typically been handled by middleware in traditional Express applications. But unlike the middleware, guards have access to the ExecutionContext instance, and this exactly what’s going to be executed next. They’re designed, much like exception filters, pipes, and interceptors, to let you interpose processing logic at exactly the right point in the request/response cycle, and to do so declaratively. So you can move this logic from services and controllers to separate file/part of the application and this helps keep your code DRY and declarative.
An interceptor is a class annotated with the @Injectable() decorator. Interceptors should implement the NestInterceptor interface.
Interceptors have a set of useful capabilities which are inspired by the Aspect-Oriented Programming (AOP) technique. They make possible to:
The method intercept() that you should implement in your Interceptor class provide you Execution Context (like Guard) and Call Handler.
Call Handler is an object which wraps the execution stream, and this defers the final handler execution.
Nest Provides the ability to implement your own custom decorator for a route. Nest provides a set of useful param decorators that you can use together with the HTTP route handlers. Below is a comparison of the decorators with the plain express objects.
For example, right out-of-the-box you get @Request() decorator for accessing to request as an object in your code. But imagine that in each request you have user field. And to get this user you need to write req.user each time. As a simplification and alternative to this, you can create custom Route Decorator @User():
import { createParamDecorator } from '@nestjs/common'; export const User = createParamDecorator((data, req) => { return req.user; });
And in your code you can use it in the next way:
@Get() async findOne(@User('test') user: UserEntity) { console.log(user); }
As you can see the application on NestJS is very similar in structure to the application on Angular. Here we have a module structure and using directives. I hope you will try to develop it.