· nodejs nestjs · 12 min read
[NestJS - Phần 2] Tích hợp Swagger vào dự án NestJS
Swagger, ra mắt năm 2011 bởi Tony Tam, là một công cụ mã nguồn mở, nó đã nhanh chóng mang đến một cuộc cách mạng cho việc tài liệu hóa API thông qua chuẩn OpenAPI một cách tự động và hiệu quả. Bài viết này giới thiệu cách tích hợp Swagger vào dự án NestJS để tự động hóa tài liệu API và hỗ trợ kiểm tra các api thông qua Swagger UI.

Phần 2: Hướng dẫn Setup Swagger cho dự án NestJS
Trong phần đầu tiên, chúng ta đã cùng nhau đi qua các phần cơ bản của NestJS. Trong phần này, bọn mình sẽ tiếp tục với việc tạo API đầu tiên với NestJS, đồng thời tích hợp Swagger vào dự án.
Mình sẽ lần lượt cùng nhau đi qua các nội dung như sau:
- 1. Tổng quan về Swagger
- 2. Swagger trong NestJS
- 3. Hướng dẫn chi tiết: Tích hợp Swagger vào dự án NestJS
- 4. Ví dụ thực tế: Gửi yêu cầu qua Swagger UI
- 5. Một số mẹo và lưu ý
- 6. Kết luận
Tổng quan về Swagger
Swagger là gì?
Swagger là một công cụ mã nguồn mở giúp chúng ta tạo tài liệu API và cung cấp giao diện tương tác để kiểm tra API. Trong lập trình, Swagger thường được nhắc đến như một phần của OpenAPI Specification, một chuẩn quốc tế cho việc mô tả API để cả con người và máy tính đều hiểu.
Với Swagger, chúng ta có thể:
- Tự động hóa tài liệu: Mô tả các endpoint, method HTTP, Request Params, Query Params và Responses của api.
- Thử nghiệm API dễ dàng: Cung cấp giao diện web (Swagger UI) để gửi yêu cầu và xem phản hồi ngay trên trình duyệt.
- Chia sẻ API: Xuất đặc tả API dưới dạng JSON/YAML để chia sẻ với các đồng nghiệp trong team của bạn.
Lịch sử tóm tắt của Swagger
Swagger được giới thiệu vào năm 2011 bởi Tony Tam, nhằm giải quyết những bất tiện khi tài liệu hóa API một cách thủ công — vốn rất dễ lỗi thời, khó cập nhật và khó duy trì. Trước đó, các lập trình viên thường phải tự viết đặc tả API bằng JSON hoặc YAML, điều này không chỉ tốn thời gian mà còn dễ sai sót.
Swagger ra đời đã thay đổi cách làm việc này bằng cách hỗ trợ sinh đặc tả API tự động từ mã nguồn, giúp đảm bảo tính chính xác và đồng bộ với hệ thống. Ngoài ra, nó còn cung cấp Swagger UI, một công cụ tạo giao diện tương tác trực quan cho phép người dùng dễ dàng xem, kiểm tra và thử nghiệm các endpoint API ngay trên trình duyệt.
- 2014: Phiên bản Swagger 2.0 cải tiến định dạng và thêm các công cụ như Swagger Editor và Codegen.
- 2015: Swagger được chuyển giao cho OpenAPI Initiative, đổi tên thành OpenAPI Specification. Điều này biến Swagger thành chuẩn mở, được các công ty lớn như Google, Microsoft hỗ trợ.
- 2016: OpenAPI 3.0 ra mắt, với nhiều tính năng hiện đại hơn, là nền tảng cho các framework như NestJS ngày nay.
Tại sao dùng Swagger trong NestJS?
- Tự động hóa tài liệu: Thay vì viết tài liệu thủ công, Swagger tự động tạo tài liệu từ mã TypeScript.
- Tăng hiệu quả phát triển: Frontend developer, tester, hoặc đối tác có thể dễ dàng hiểu và thử nghiệm API.
- Tiết kiệm thời gian: Swagger UI cho phép kiểm tra API mà không cần công cụ như Postman.
- Chuẩn hóa: Đặc tả API được tạo ra có thể dùng để sinh mã nguồn.
Swagger trong NestJS
Trong NestJS, Swagger được tích hợp qua thư viện @nestjs/swagger
, hoạt động như sau:
- Đọc mã TypeScript: Thư viện phân tích các controller, DTO, và decorator trong mã nguồn để trích xuất thông tin về API.
- Tạo đặc tả OpenAPI: Chuyển đổi thông tin thành định dạng JSON hoặc YAML theo chuẩn OpenAPI 3.0.
- Hiển thị Swagger UI: Tạo một giao diện web để bạn xem tài liệu API và thử nghiệm các endpoint.
Cơ chế tự động hóa tài liệu
Thay vì viết file JSON/YAML thủ công, @nestjs/swagger
tự động tạo đặc tả OpenAPI từ mã TypeScript nhờ các bước sau (NestJS OpenAPI Documentation):
- Sử dụng decorator: Các decorator như
@ApiProperty
,@ApiOperation
, và@ApiResponse
được sử dụng để cung cấp metadata cho các DTO và controller. Ví dụ,@ApiProperty
định nghĩa mô tả, kiểu dữ liệu, hoặc giá trị ví dụ cho các thuộc tính của DTO. - Tạo đặc tả theo chuẩn OpenAPI:
@nestjs/swagger
sử dụng SwaggerModule để sinh ra tài liệu OpenAPI (dạng JSON hoặc YAML) dựa trên metadata từ mã nguồn. Quá trình này được thực hiện thông qua phương thứcSwaggerModule.createDocument
. - Tự động tương tác với mã nguồn: Mỗi khi mã nguồn thay đổi (thêm endpoint, sửa DTO), đặc tả được cập nhật mà không cần chỉnh sửa thủ công.
Ví dụ, với một DTO như:
class CreateUserDto {
@ApiProperty({ description: 'The name of the user', example: 'John Doe' })
name: string;
}
@nestjs/swagger
tự động tạo một phần đặc tả JSON:
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "The name of the user", "example": "John Doe" }
}
}
Kết quả là tài liệu API luôn đồng bộ với mã nguồn và sẵn sàng hiển thị trong Swagger UI.
Hướng dẫn chi tiết: Tích hợp Swagger vào dự án NestJS
Dưới đây là các bước cụ thể để tạo một API đơn giản và tích hợp Swagger vào dự án NestJS. Mình giả định bạn đã cài đặt NestJS CLI (npm i -g @nestjs/cli
). Nếu chưa có dự án, tạo mới bằng lệnh:
nest new my-project
cd my-project
Sau khi chạy hai lệnh trên thì bạn đã tạo được một dự án mới, đồng thời bạn cũng đang trong cửa sổ cmd của thư mục dự án. Giờ thì chúng ta cùng bắt tay vào việc tạo một api mới. Nếu có thắc mắc hoặc chưa biết cách tạo bạn có thể xem lại phần 1 tại đây.
Bước 1: Tạo API đầu tiên với NestJS
Chúng ta sẽ tạo một API đơn giản để quản lý người dùng (users) với hai endpoint: lấy danh sách người dùng (GET /users
) và tạo người dùng mới (POST /users
).
Tạo Module
Chạy lệnh để tạo module users
:
nest generate module users
Tạo Service
Tạo service để xử lý logic:
nest generate service users
Mở file users.service.ts
và thêm logic cơ bản, ở đây mình thêm phương thức findAll()
để lấy tất cả các user và create()
để tạo một user mới:
import { Injectable } from '@nestjs/common';
export interface User {
id: number;
name: string;
email: string;
}
@Injectable()
export class UsersService {
private users: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
];
findAll(): User[] {
return this.users;
}
create(user: Omit<User, 'id'>): User {
const newUser = { id: this.users.length + 1, ...user };
this.users.push(newUser);
return newUser;
}
}
Tạo DTO
Tiếp theo là tạo DTO (Data Tranform Object) đây là một đối tượng mà nó có chức năng cấu trúc dữ liệu đầu vào, ngoài ra nó còn hỗ trợ bạn validate, transform dữ liệu một cách an toàn và nhanh chóng.
Bắt đầu, bạn tạo file create-user.dto.ts
trong thư mục users
:
export class CreateUserDto {
name: string;
email: string;
}
Tạo Controller
Tiếp tục chúng ta sẽ bắt tay vào tạo controller, nơi đây sẽ là nơi đón nhận các request từ client.
nest generate controller users
Mở file users.controller.ts
và thêm hai endpoint, hai endponit này định nghĩa hai phương thức findAll()
và create()
tương ứng nó sẽ gọi đến các services cùng tên, mình xin lưu ý rằng việc cùng tên ở đây là để dễ nhớ chứ không có một nguyên tắc nào, bạn có thể đặt tên tuỳ ý miễn sao nó gọi đúng đến services thực hiện công việc bạn muốn:
import { Controller, Get, Post, Body } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './create-user.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
Đăng ký Module
Chúng ta cần kiểm tra lại app module, để đảm bảo rằng UsersModule
được import trong app.module.ts
:
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule], // Nơi import module user vừa tạo
})
export class AppModule {}
Kiểm tra hoạt động của các API
Sau các bước trên, ứng dụng của chúng ta đã sẵn sàng. Để chắc chắn rằng các api đã hoạt động tốt, bạn cùng mình test thử nhé. Đầu tiền là khởi chạy ứng dụng với lệnh:
npm run start
Sau đó chúng ta mở cmd và nhập:
curl -X GET "http://localhost:3000/users/"
Kết quả nhận được sẽ là:
[{"id":1,"name":"John Doe","email":"john@example.com"}]
Đây là một mảng các users có trong danh sách.
Tương tự, mình tiếp tục thử tạo một user nhé:
curl -X POST "http://localhost:3000/users/" -H "accept: */*" -H "Content-Type: application/json" -d "{\"name\": \"Nguyen Van A\", \"email\": \"nguyenvana@example.com\"}"
Kết quả là:
{"id":2,"name":"Nguyen Van A","email":"nguyenvana@example.com"}
Với việc gửi yêu cầu tạo user mới, dữ liệu mà chúng ta nhận được từ response là user mà chúng ta vừa gửi yêu cầu tạo. Phản hồi này tương ứng với việc user mới đã được tạo thành công.
Sau khi hoàn thành hai bước trên, hai api mà chúng ta vừa tạo được đảm bảo hoạt động đúng chức năng. Sẵn sàng cho bước kế tiếp.
Cài đặt các thư viện Swagger
Giờ thì đến phần quan trọng rồi, Chúng ta sẽ tiến hành cài đặt Swagger bằng việc cài đặt hai packages là @nestjs/swagger
và swagger-ui-express
:
npm install @nestjs/swagger swagger-ui-express
Cấu hình Swagger trong ứng dụng
Sau cài đặt thành công ở bước trên, chúng ta sẽ bắt đầu đưa Swagger vào dự án thông qua cấu hình trong file main.ts
của ứng dụng. Bạn mở file main.ts
và thêm các dòng sau:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Cấu hình Swagger
const config = new DocumentBuilder()
.setTitle('My API') // Thêm tiêu đề cho Swagger UI
.setDescription('The API documentation for my NestJS application') // Thêm mô tả cho Swagger UI
.setVersion('1.0') // Phiên bản ứng dụng của bạn
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document); // Đặt endpoint /docs cho Swagger UI bạn có để đặt tên tuỳ ý.
await app.listen(3000);
}
bootstrap();
Cập nhật các decorator
Cập nhật file create-user.dto.ts
trong thư mục users
:
+ import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
+ @ApiProperty({ description: 'The name of the user', example: 'John Doe' })
name: string;
+ @ApiProperty({ description: 'The email of the user', example: 'john@example.com' })
email: string;
}
Cập nhật users.controller.ts
trong thư mục users
import { Controller, Get, Post, Body } from '@nestjs/common';
+ import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { CreateUserDto } from './create-user.dto';
+ @ApiTags('users') // Nhóm các endpoint dưới tag 'users'
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
+ @ApiOperation({ summary: 'Get all users' })
+ @ApiResponse({ status: 200, description: 'Return all users' })
findAll() {
return this.usersService.findAll();
}
@Post()
+ @ApiOperation({ summary: 'Create a new user' })
+ @ApiResponse({ status: 201, description: 'User created successfully' })
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
Sau bước trên là coi như đã hoàn thành việc cài đặt và cấu hình cho Swagger. Kế tiếp chúng ta sẽ bắt đầu khởi chạy và tiến hành kiểm tra.
Chạy ứng dụng và kiểm tra Swagger UI
Chạy dự án:
npm run start
Mở trình duyệt và truy cập
http://localhost:3000/docs
. Bạn sẽ thấy Swagger UI hiển thị:- Danh sách endpoint (
GET /users
,POST /users
). - Mô tả chi tiết về tham số (
name
,email
trong DTO). - Nút “Try it out” để gửi yêu cầu và xem phản hồi.
- Danh sách endpoint (
Ví dụ thực tế: Gửi yêu cầu qua Swagger UI
Tại http://localhost:3000/docs
, thử các thao tác sau:
Nhấn vào endpoint
GET /users
> Try it out > Execute để xem danh sách người dùng.
Chúng ta có phản hồi sau:Nhấn vào endpoint
POST /users
> Try it out, nhập dữ liệu:{ "name": "Jane Doe", "email": "jane@example.com" }
Nhập xong, bạn tếp tục nhấn vào excute Execute để gửi yêu cầu POST và xem phản hồi. Kết quả nhận được sẽ là:
Một số mẹo và lưu ý
Sau khi hoàn thành, mình có một số lưu ý cũng như thông tin cho các bạn một số vấn đề sau:
- Bảo mật Swagger UI: Trong môi trường production, chúng ta nên giới hạn truy cập vào endpoint
/docs
(ví dụ: chỉ cho phép trong môi trường dev) để tránh lộ thông tin API. - Tùy chỉnh Swagger UI: Khi ứng dụng phát triển lớn, cần tích hợp các cơ chế bảo mật thì chúng ta có thể thêm xác thực (như JWT) hoặc thay đổi giao diện bằng cách cấu hình thêm trong
DocumentBuilder
. - Xuất đặc tả OpenAPI: Chúng ta hoàn toàn có thể lưu đặc tả JSON/YAML bằng
SwaggerModule.createDocument
để dễ dàng chia sẻ với team. - Hiệu suất: Với những dự án lớn, việc tạo tài liệu Swagger có thể làm chậm khởi động ứng dụng. Chúng ta nên xem xét tắt Swagger trong production để đảm bảo hiệu suất cho ứng dụng.
Kết luận
Vậy là chúng ta đã hoàn thành việc tích hợp Swagger vào NestJS, đây là một bước quan trọng để tự động hóa tài liệu API và nâng cao hiệu quả phát triển ứng dụng. Với @nestjs/swagger
, bạn có thể dễ dàng tạo ra tài liệu API đồng bộ với mã nguồn và thử nghiệm các endpoint ngay trên trình duyệt. Bài viết này đã hướng dẫn bạn tạo một API đơn giản và tích hợp Swagger, từ việc thiết lập dự án đến kiểm tra kết quả thông qua Swagger UI.
Tiếp theo, trong Phần 3: Setup TypeORM Database, chúng ta sẽ cũng nhau học cách tích hợp TypeORM vào dự án NestJS để lưu trữ dữ liệu người dùng vào cơ sở dữ liệu thực tế, thay vì sử dụng mảng tạm thời như trong ví dụ này. Điều này sẽ giúp các API trở nên mạnh mẽ và sẵn sàng cho các ứng dụng thực tế. Rất mong nhận được sự đón nhận của các bạn.