NestJS cho người mới: module, controller và provider

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Nếu Express giống một hộp đồ nghề để bạn tự lắp, thì NestJS là một bộ khung có sẵn cấu trúc, rất quen thuộc với ai từng dùng Angular hay Spring. Dùng TypeScript và dependency injection, Nest giúp các dự án Node.js lớn vẫn giữ được trật tự.

Ba khái niệm cốt lõi

Một ứng dụng Nest được tạo từ ba loại thành phần:

  • Module: nhóm các thành phần liên quan thành một khối chức năng, ví dụ UsersModule.
  • Controller: nhận request HTTP, định tuyến và trả phản hồi.
  • Provider (thường là service): chứa logic nghiệp vụ, được tiêm vào nơi cần dùng.

Cách chia này giúp bạn biết ngay mỗi đoạn code nên nằm đâu, và các nhóm chức năng ít phụ thuộc vào nhau.

Khởi tạo dự án

npm i -g @nestjs/clinest new my-apicd my-apinest generate resource users

Lệnh cuối sinh sẵn module, controller, service và DTO cho tài nguyên users. Nest dùng decorator (các chú thích bắt đầu bằng @) để khai báo ý nghĩa của class và phương thức.

Controller và Service

@Controller('users')export class UsersController {  constructor(private readonly usersService: UsersService) {}  @Get()  findAll() {    return this.usersService.findAll();  }  @Get(':id')  findOne(@Param('id', ParseIntPipe) id: number) {    return this.usersService.findOne(id);  }  @Post()  create(@Body() dto: CreateUserDto) {    return this.usersService.create(dto);  }}
@Injectable()export class UsersService {  private users = [{ id: 1, name: 'An' }];  findAll() { return this.users; }  findOne(id: number) {    const user = this.users.find((u) => u.id === id);    if (!user) throw new NotFoundException('Không tìm thấy người dùng');    return user;  }}

Service được khai báo @Injectable() và đăng ký trong module; Nest tự tạo và tiêm nó vào constructor của controller. Bạn không cần dùng new.

Validation bằng DTO và Pipe

DTO (Data Transfer Object) mô tả hình dạng dữ liệu vào. Kết hợp với class-validator và ValidationPipe, Nest tự động từ chối dữ liệu sai:

export class CreateUserDto {  @IsString()  @MinLength(2)  name: string;  @IsEmail()  email: string;}// main.tsapp.useGlobalPipes(new ValidationPipe({ whitelist: true }));

Tùy chọn whitelist loại bỏ các trường không khai báo trong DTO, giúp tránh việc client gửi thêm trường lạ.

Guard, Interceptor và Exception Filter

Nest có sẵn các điểm mở rộng cho những mối quan tâm cắt ngang:

  • Guard: quyết định request có được đi tiếp không, thường dùng cho xác thực và phân quyền.
  • Interceptor: bao quanh việc thực thi, dùng để ghi log, biến đổi phản hồi, cache.
  • Exception Filter: chuẩn hóa cách trả lỗi.
  • Pipe: biến đổi và kiểm tra tham số.
@UseGuards(AuthGuard)@Get('me')getProfile(@Req() req) {  return req.user;}

Khi nào chọn NestJS?

NestJS phù hợp khi dự án có nhiều người cùng làm, cần cấu trúc rõ ràng, nhiều module và muốn dễ kiểm thử nhờ dependency injection. Nó cũng có tích hợp tốt với TypeORM, Prisma, GraphQL, WebSocket và hàng đợi. Đổi lại, nó có đường cong học tập cao hơn Express và nhiều "ma thuật" của decorator. Với một API nhỏ vài endpoint, Express hoặc Fastify thuần có thể đủ và nhẹ hơn. Hãy chọn theo quy mô và đội ngũ của bạn, chứ không phải vì xu hướng.

Kiểm thử thuận lợi

Nhờ dependency injection, bạn dễ dàng thay thế service thật bằng bản giả khi kiểm thử controller. Nest cung cấp Test.createTestingModule để dựng module thử nghiệm với các provider giả, nên các bài unit test chạy nhanh và độc lập với database.

Cấu trúc thư mục và module hóa

Khi dự án lớn dần, hãy chia theo tính năng thay vì theo loại file. Mỗi thư mục như users, orders, payments chứa module, controller, service, DTO và entity của riêng nó. Một module chỉ xuất ra (exports) những provider mà module khác thật sự cần dùng, và khai báo rõ phụ thuộc qua imports. Cách làm này giữ ranh giới rõ ràng, giảm tình trạng code chằng chịt, và sau này nếu cần tách một module thành dịch vụ riêng, công việc sẽ nhẹ nhàng hơn nhiều.

Nest cũng hỗ trợ cấu hình theo môi trường với ConfigModule, đọc biến từ file .env và kiểm tra tính hợp lệ lúc khởi động. Hãy dùng nó thay vì đọc trực tiếp process.env ở khắp nơi, để lỗi thiếu cấu hình được phát hiện ngay khi chạy ứng dụng thay vì lúc đang xử lý request.

Lời khuyên học NestJS

Hãy đọc tài liệu chính thức theo thứ tự: tổng quan, controller, provider, module, rồi mới tới guard, pipe, interceptor. Sau mỗi phần, tự viết lại ví dụ thay vì sao chép. Hãy luôn kiểm tra lại bằng thực hành thay vì chỉ đọc lý thuyết: dựng một dự án nhỏ, cố tình tạo lỗi, quan sát log và công cụ gỡ lỗi, rồi sửa. Khi đã quen, thử tích hợp một ORM như Prisma hoặc TypeORM và viết vài bài kiểm thử end-to-end bằng Supertest để thấy cả vòng đời một request.

Kết luận

Hãy bắt đầu bằng một tài nguyên đơn giản như danh sách công việc, thử sinh bằng nest generate resource và đọc kỹ code được tạo ra. Khi đã quen module, controller, provider, bạn đã nắm hơn một nửa NestJS.

Khi cần một lộ trình học có hệ thống, bạn có thể tham khảo khóa học trên codebem.com.

author_photo
Nguyễn Đình Cường

0 comment