Tìm hiểu về NestJS (Phần 2)

NamDev

Guest
Trong bài viết trước, mình đã giới thiệu về NestJS và các thành phần cơ bản của framework này cũng như xây dựng demo một api bằng NestJS. Như mình đã giới thiệu, NestJS có một hệ sinh thái hỗ trợ cho chúng ta trong quá trình phát triển mà các framework khác như Express, Fastify,... phải tự build hoặc sử dụng các lib do cộng đồng phát triển. Trong bài viết này, mình sẽ giới thiệu về các thành phần đó cũng như cách apply chúng vào dự án NestJS của bạn.
1. Middleware


Middleware là một function được thực hiện trước hàm xử lý route để thực hiện một tác vụ nhất định nào đó. Ở một số framework như Express thì Middleware thường được xử dụng để xác thực user, permission, validate data,.. nhưng ở NestJS việc xác thực hay validate đã có các thành phần riêng biệt đảm nhận nhiệm vụ này như PipesGruads nên bạn sẽ không phải dùng đến Middleware nữa. Tuy nhiên, không chỉ có xác thực mà middleware còn làm rất nhiều nhiệm vụ khác tuỳ theo mục đích xử lý của trong api của bạn.

Trong NestJS, Middleware có thể được tạo ra bằng function hoặc class. Mình sẽ demo về 2 cách tạo middleware bên dưới đây

Với class bạn cần define @Injectable() và implement NestMiddleware. Như trong bài trước mình đã nói, @Injectable() sẽ đưa class của bạn vào DI Container để khởi tạo và quản lý cũng như truyền phụ thuộc vào các bạn mà nó được sử dụng nhé.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...');
next();
}
}


Để triển khai Middleware vào các router, NestJS cung cấp interface NestModule với phương thức configure cho phép apply Middleware vào các route tương ứng trong forRoutes() .Tại app.module.ts chúng ta config như sau:

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('cats');
}
}


Ngoài ra trong controller /cats, chúng ta có thể apply Middleware theo request method tương ứng bằng cách truyền tham số { path: String, method: RequestMethod } vào forRoutes. Việc config như dưới đây sẽ hạn chế sử dụng Middleware trong các request không cần sử dụng chúng:

import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET });
}
}


Với multiple middleware bạn chỉ cần truyền các middleware vào apply() như các tham số:

consumer.apply(cors(), helmet(), logger).forRoutes('cats');

Đối với middleware đơn giản như LoggerMiddleware mình nhận thấy sử dụng class là không cần thiết vì nó không có phụ thuộc hay các phương thức xử lý phức tạp khác. Vì vậy chúng ta có thể sử dụng function middleware để thực hiện nhiệm vụ này

import { Request, Response, NextFunction } from 'express';

export function logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`);
next();
};

Và tất nhiên rồi, việc apply chúng cũng giống như class:

consumer
.apply(logger)
.forRoutes(CatsController);
 
Bên trên