Trong bài viết này, chúng ta sẽ giới thiệu cách xử lý lỗi, validation, và logging trong RESTful APIs của Nest.js. Chúng ta sẽ giải thích cách tạo các middleware để validation, handlers để xử lý lỗi, và sử dụng logger để ghi lại các sự kiện và nội dung của API.
Phần I: Validation
Validation đóng vai trò rất quan trọng trong việc đảm bảo tính toàn vẹn của dữ liệu nhận được từ các API request. Trong Nest.js, chúng ta có thể sử dụng một số thư viện validation như class-validator hoặc Joi để đơn giản hóa quá trình validation.
1. Cài đặt class-validator
Để sử dụng class-validator, cài đặt nó bằng npm:
npm install class-validator class-transformer
2. Sử dụng class-validator
Class-validator là một thư viện hỗ trợ validation tự động bằng cách sử dụng decorators như @IsEmail(), @Length(min, max), @IsNotEmpty(), vv.
Chẳng hạn, để kiểm tra xem địa chỉ email có hợp lệ không, ta sử dụng decorator @IsEmail() như sau:
import { IsEmail } from 'class-validator';
export class UserSignUpDto {
@IsEmail()
email: string;
password: string;
}
Khi user payload được gửi từ request body, Nest.js sẽ tự động áp dụng validation để kiểm tra xem email có hợp lệ không.
3. Sử dụng middleware để xử lý validation
Để kiểm tra các object payload từ các request, chúng ta sử dụng middleware. Middleware được định nghĩa để chạy trước khi handler xử lý request và có thể được sử dụng để kiểm tra thông tin đầu vào trong các API request.
Để sử dụng middleware, ta có thể chỉ định bằng cách sử dụng decorator @UseMiddleware() trong controller class.
Trong ví dụ sau đây, ta sử dụng thư viện class-validator kết hợp với Nest.js và Joi để sử dụng middleware validation cho một đối tượng request.
import { Controller, Post, Body, UsePipes, UseGuards } from '@nestjs/common';
import { UserService } from './user.service';
import { JoiValidationPipe } from '../shared/pipes/joi-validation-pipe.pipe';
import { CreateUserDto } from './dto/create-user.dto';
import { IsEmail, IsNotEmpty, Length } from 'class-validator';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RequestValidationPipe } from '../shared/pipes/request-validation.pipe';
export class CreateUserBodyDto {
@IsEmail()
email: string;
@IsNotEmpty()
@Length(8, 32)
password: string;
}
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@UseGuards(JwtAuthGuard)
@Post()
@UsePipes(RequestValidationPipe, JoiValidationPipe(CreateUserBodyDto))
async create(@Body() createUserDto: CreateUserDto): Promise {
return this.userService.create(createUserDto);
}
}
Ở đây, chúng ta có một middleware tùy chỉnh JoiValidationPipe để kiểm tra Validate tất cả các trường trong CreateUserBodyDto. Sau đó, middleware RequestValidationPipe sẽ kiểm tra tất cả các trường như một object trên request, đảm bảo rằng tất cả các thông tin đầu vào đều hợp lệ.
Phần II: Error Handling
Tiếp theo, chúng ta sẽ giới thiệu cách xử lý lỗi trong Nest.js RESTful APIs.
1. Lỗi thông thường của Nest.js
Trong Nest.js, các lỗi thông thường như "Not Found", "Internal Server Error", hay "Bad Request" được xử lý bằng cách sử dụng built-in exceptions hoặc status code.
Ví dụ:
import { NotFoundException } from '@nestjs/common';
throw new NotFoundException('User not found');
Method trên sẽ bị ném ra NotFoundException, và mã HTTP response của API sẽ là 404, kèm theo nội dung "User not found".
2. Error Handler
Để xử lý các exception, chúng ta có thể sử dụng @Catch() decorator với exception filter.
Ví dụ, hãy xem xét trường hợp xử lý UnauthorizedException trong ứng dụng Nest.js:
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
import { UnauthorizedException } from '@nestjs/common';
@Catch(UnauthorizedException)
export class UnauthorizedExceptionFilter implements ExceptionFilter {
catch(exception: UnauthorizedException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(401).json({
statusCode: 401,
message: 'Unauthorized',
error: 'Unauthorized',
});
}
}
Ở đây, chúng ta sử dụng @Catch(UnauthorizedException) để lắng nghe exception của UnauthorizedException. Trong trường hợp này, chúng ta định nghĩa một UnauthorizedExceptionFilter để xử lý các exception đã ném ra trước đó.
Phần III: Logging
Cũng như bất kỳ ứng dụng nào khác, chúng ta cần ghi lại các sự kiện của ứng dụng để có thể debug và monitor trạng thái của ứng dụng. Trong Nest.js, chúng ta có thể sử dụng các logger như Winston hoặc Morgan để đáp ứng nhu cầu của ứng dụng của chúng ta.
1. Cài đặt Winston
Trong Nest.js, chúng ta có thể sử dụng logger được hỗ trợ sẵn bởi Nest.js hoặc sử dụng các logger khác như Winston. Ở đây, chúng tôi sử dụng Winston do đây là một logger phổ biến được sử dụng rộng rãi.
Để bắt đầu, chúng ta cần cài đặt Winston bằng npm:
npm install winston
2. Sử dụng Winston
Sau khi cài đặt Winston, chúng ta có thể sử dụng logger cho ứng dụng Nest.js của mình.
Trong class logger, sử dụng Winston logger bằng cách khởi tạo logger như sau:
import * as winston from 'winston';
export class AppLogger {
private logger: winston.Logger;
}
Ở đây, chúng ta khai báo logger bằng cách sử dụng winston.Logger.
Trong constructor của class logger, cấu hình logger:
import * as winston from 'winston';
export class AppLogger {
private logger: winston.Logger;
constructor() {
this.logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console({
format: winston.format.simple(),
}),
],
});
}
}
Ở đây chúng ta cấu hình logger level là "info", output JSON, và console transport.
Cuối cùng, để sử dụng logger bằng cách gọi logger.log() và truyền vào level và thông điệp cần ghi lại:
import { Injectable } from '@nestjs/common';
import { AppLogger } from '../logger/winston.logger';
@Injectable()
export class UserService {
constructor(private readonly appLogger: AppLogger) {}
async create(createUserDto: CreateUserDto): Promise {
this.appLogger.log('info', `Creating user ${createUserDto.email}`);
// code logic to create user
return { success: true };
}
}
Ở đây, chúng ta sử dụng logger để ghi lại thông tin về hành động của ứng dụng, trong trường hợp này là tạo mới một user mới.
Như vậy trong bài viết về Error Handling, Validation, và Logging trong Nest.js RESTful APIs, chúng ta đã tìm hiểu cách validation các API request payloads, xử lý các lỗi thông thường trong Nest.js, và sử dụng logger để ghi lại các sự kiện của ứng dụng. Các chức năng này là rất quan trọng để đảm bảo tính toàn vẹn và ổn định của các ứng dụng của bạn.
