How to quickly get started with VUE3.0: Enter and learn
Nest.js is a back-end framework of Nodejs. It encapsulates express and other http platforms to solve architectural problems. It provides MVC, IOC, AOP and other architectural features that express does not have, making the code easier to maintain and expand.
What do MVC, IOC, and AOP here mean? Let's look at them separately:
MVC is the abbreviation of Model View Controller. Under the MVC architecture, the request will first be sent to the Controller, which will dispatch the Service of the Model layer to complete the business logic, and then return the corresponding View.
Nest.js provides the @Controller decorator to declare Controller:
The Service will be declared with the @Injectable decorator:
Classes declared through @Controller and @Injectable decorators will be scanned by Nest.js, corresponding objects will be created and added to a container. All these objects will be automatically injected according to the dependencies declared in the constructor, that is, DI (dependency inject) ), this idea is called IOC (Inverse Of Control).
The advantage of the IOC architecture is that there is no need to manually create objects and pass them into the constructors of different objects based on dependencies. Everything is automatically scanned, created, and injected.
In addition, Nest.js also provides the ability of AOP (Aspect Oriented Programming), which is the ability of aspect-oriented programming:
What does AOP mean? What is aspect-oriented programming?
A request may go through the logic of Controller, Service, and Repository (database access):
If you want to add some general logic to this call link, how should you add it? Such as logging, permission control, exception handling, etc.
What is easy to think of is to directly transform the Controller layer code and add this logic. This works, but it's not elegant because these common logics invade the business logic. Can we transparently add logs, permissions, etc. to these business logics?
Is it possible to add a stage to execute common logic before and after calling the Controller?
For example:
Such horizontal expansion points are called aspects, and this programming method that transparently adds some aspect logic is called AOP (aspect-oriented programming).
The advantage of AOP is that it can separate some general logic into aspects and keep the business logic pure. In this way, the aspect logic can be reused and dynamically added and deleted.
In fact, the onion model of Express's middleware is also an implementation of AOP, because You can wrap a layer on the outside transparently and add some logic, and the inner layer will not be perceptible.
Nest.js has more ways to implement AOP, there are five in total, including Middleware, Guard, Pipe, Inteceptor, ExceptionFilter:,
Nest.js is based on Express and can naturally use middleware, but it has been further subdivided. , divided into global middleware and routing middleware:
global middleware is the middleware of Express. Some processing logic is added before and after the request. Each request will go here:
Routing middleware is for a certain route, with a smaller scope:
This concept directly inherits Express and is easier to understand.
Let’s take a look at some Nest.js extended concepts, such as Guard:
Guard means routing guard. It can be used to determine permissions before calling a Controller and return true or false to decide whether to release:
The way to create a Guard is as follows:
Guard needs to implement the CanActivate interface and the canActive method. It can get the requested information from the context, and then perform some permission verification and other processing before returning true or false.
Add it to the IOC container through the @Injectable decorator, and then enable it in a Controller:
The Controller itself does not need to be modified, but the logic of permission judgment is transparently added. This is the benefit of the AOP architecture.
And, just like Middleware supports global and route levels, Guard can also be enabled globally:
Guard can abstract the access control logic of routing, but cannot modify requests and responses. This logic can use Interceptor:
Interceptor means interceptor. You can add some logic before and after the target Controller method:
The way to create an Inteceptor is as follows:
Interceptor needs to implement the NestInterceptor interface and the intercept method. Calling next.handle() will call the target Controller. You can add some processing logic before and after.
The processing logic before and after the Controller may be asynchronous. Nest.js organizes them through rxjs, so you can use various operators of rxjs.
Interceptor supports each route being enabled individually, which only affects a certain controller, and it also supports global enablement, which affects all controllers:
In addition to the permission control of routes and the processing before and after the target Controller, which are all common logic, the processing of parameters is also a common logic, so Nest.js also extracts the corresponding aspects, that is, Pipe:
Pipe means pipe. , used to do some verification and conversion of parameters:
The way to create a Pipe is as follows:
Pipe needs to implement the PipeTransform interface and the transform method, which can perform parameter verification on the incoming parameter value, such as whether the format and type are correct. If it is not correct, an exception will be thrown. You can also perform conversion and return the converted value.
There are 8 built-in Pipes, and their meanings can be seen from the names:
ValidationPipe
ParseIntPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
DefaultValuePipe
ParseEnumPipe
ParseFloatPipe
Similarly, Pipe can only take effect on a certain route, or it can take effect on every route:
Whether it is Pipe, Guard, Interceptor or the Controller that is finally called, some exceptions can be thrown during the process. How to respond to certain exceptions?
This mapping of exceptions to responses is also a common logic. Nest.js provides ExceptionFilter to support:
ExceptionFilter can handle thrown exceptions and return corresponding responses:
The form of creating ExceptionFilter is as follows:
First, you need to implement the ExceptionFilter interface and the catch method to intercept exceptions. However, what exceptions you want to intercept need to be declared with the @Catch decorator. After intercepting the exception, you can respond with the exception corresponding to give the user a more friendly prompt.
Of course, not all exceptions will be handled. Only exceptions that inherit HttpException will be handled by ExceptionFilter. Nest.js has many built-in subclasses of HttpException:
BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableException
InternalServerErrorException
NotImplementedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException
Of course, You can also extend it yourself:
Nest.js realizes the correspondence between exceptions and responses in this way. As long as different HttpExceptions are thrown in the code, the corresponding responses will be returned, which is very convenient.
Similarly, ExceptionFilter can also choose to take effect globally or take effect on a certain route:
a certain route:
Global:
We understand the AOP mechanism provided by Nest.js, but what is their order relationship?
Middleware, Guard, Pipe, Interceptor, and ExceptionFilter, can transparently add certain processing logic to a certain route or all routes. This is the benefit of AOP.
But what is the sequential relationship between them?
The calling relationship depends on the source code.
The corresponding source code is as follows:
Obviously, when entering this route, Guard will be called first to determine whether there is permission, etc. If there is no permission, an exception will be thrown here:
The HttpException thrown will be handled by ExceptionFilter.
If you have permission, the interceptor will be called. The interceptor organizes a chain, calls one by one, and finally calls the controller method:
Before calling the controller method, pipe will be used to process the parameters:
Each parameter will be converted:
It is easy to think of the calling timing of ExceptionFilter, which is to handle the exception before responding.
Middleware is a concept in express, Nest.js just inherits it, and it is called at the outermost layer.
This is the calling sequence of these AOP mechanisms. Once you have these things sorted out, you will have a good grasp of Nest.js.
Nest.js is encapsulated based on the express http platform, and applies architectural ideas such as MVC, IOC, and AOP.
MVC is the division of Model and View Controller. The request first passes through the Controller, then calls the Service and Repository of the Model layer to complete the business logic, and finally returns the corresponding View.
IOC means that Nest.js will automatically scan classes with @Controller and @Injectable decorators, create their objects, and automatically inject the objects it depends on based on dependencies, eliminating the trouble of manually creating and assembling objects.
AOP extracts general logic and adds it to a certain place through aspects. It can reuse and dynamically add and delete aspect logic.
Nest.js's Middleware, Guard, Interceptor, Pipe, and ExceptionFileter are all implementations of AOP ideas. They are just aspects at different locations. They can all be flexibly applied to a certain route or all routes. This is the advantage of AOP.
We looked at their calling sequence through the source code. Middleware is the concept of Express. In the outermost layer, after reaching a certain route, Guard will be called first. Guard is used to determine whether the route has permission to access, and then Interceptor will be called. Expand some logic back and forth, and call Pipe to verify and convert parameters before reaching the target Controller. All HttpException exceptions will be handled by ExceptionFilter and return different responses.
Nest.js uses this AOP architecture to achieve a loosely coupled, easy-to-maintain and expand architecture.
Have you felt the benefits of AOP architecture?