REST API: Hướng Dẫn Hoàn Chỉnh Từ A-Z Cho Web Developer
Tìm hiểu REST API từ A-Z: nguyên tắc cốt lõi, HTTP methods, status codes, thiết kế URL chuẩn, pagination, versioning, bảo mật và những best practices giúp bạn thiết kế API chuyên nghiệp.

Bạn đã bao giờ mở tab Network trong DevTools và thấy hàng loạt request tới /api/users, /api/posts, /api/login? Hay khi build một website cần lấy dữ liệu từ backend, bạn tự hỏi: “API nên được thiết kế thế nào cho đúng chuẩn?”
Dù bạn là frontend developer gọi API mỗi ngày hay backend developer bắt đầu xây dựng API đầu tiên, hiểu rõ REST API là kỹ năng không thể thiếu — nó là “ngôn ngữ chung” giữa client và server trên toàn bộ internet hiện đại.
Trong bài viết này, chúng ta sẽ đi từ khái niệm cốt lõi, qua HTTP methods, status codes, thiết kế URL, đến pagination, versioning, bảo mật và những best practices thực tế để tạo ra một REST API chuyên nghiệp.
REST API là gì?
REST (viết tắt của REpresentational State Transfer) là một kiến trúc thiết kế API do Roy Fielding giới thiệu trong luận án tiến sĩ năm 2000. Ý tưởng cốt lõi: hệ thống web đã có sẵn những “nguyên liệu” tuyệt vời là HTTP, vậy tại sao không tận dụng chúng để thiết kế API?
Một API được gọi là RESTful khi nó tuân theo các ràng buộc kiến trúc của REST:
1. Client-Server (Tách biệt client và server)
Client (trình duyệt, mobile app, ứng dụng khác) và server hoàn toàn độc lập. Server không quan tâm giao diện, client không quan tâm lưu trữ. Điều này giúp cả hai phát triển riêng biệt — một API có thể phục vụ website, mobile app và smart TV cùng lúc.
2. Stateless (Không lưu trạng thái)
Mỗi request phải tự mang đủ thông tin để server xử lý. Server không lưu trạng thái phiên giữa các request.
# Request 1 — Không hợp lệ trong REST thuần túy
GET /api/orders/123
# Server: "Order nào? Bạn đã đăng nhập lúc nãy ở request trước mà?"
# Request 2 — Đúng chuẩn: tự mang token xác thực
GET /api/orders/123
Authorization: Bearer <access-token>
3. Cacheable (Có thể cache)
Response phải khai báo rõ có cache được hay không, thông qua headers như Cache-Control, ETag. Cache tốt giúp giảm tải server và tăng tốc độ đáng kể.
4. Uniform Interface (Giao diện đồng nhất)
Là ràng buộc quan trọng nhất, gồm 4 phần:
- Resource identification: mỗi tài nguyên có định danh riêng (URL)
- Representation: client nhận dữ liệu qua JSON, XML… — không nhận trực tiếp database
- Self-descriptive messages: mỗi request/response tự mô tả đầy đủ
- HATEOAS: (nâng cao) response chứa link điều hướng tới các hành động tiếp theo
5. Layered System (Hệ thống phân lớp)
Client không cần biết server có proxy, load balancer, cache layer hay không. Các lớp trung gian có thể được thêm bớt mà không ảnh hưởng đến client.
6. Code on Demand (Tùy chọn)
Server có thể gửi code (ví dụ JavaScript) để client thực thi. Đây là ràng buộc duy nhất không bắt buộc.
HTTP Methods — “Động từ” của REST
REST dùng HTTP methods để mô tả hành động lên tài nguyên:
| Method | Chức năng | Idempotent? | An toàn? | Ví dụ |
|---|---|---|---|---|
GET | Lấy dữ liệu | ✅ | ✅ | GET /api/users |
POST | Tạo tài nguyên mới | ❌ | ❌ | POST /api/users |
PUT | Thay thế toàn bộ tài nguyên | ✅ | ❌ | PUT /api/users/42 |
PATCH | Cập nhật một phần | ❌ | ❌ | PATCH /api/users/42 |
DELETE | Xóa tài nguyên | ✅ | ❌ | DELETE /api/users/42 |
HEAD | Lấy header giống GET, không body | ✅ | ✅ | HEAD /api/users |
OPTIONS | Mô tả phương thức được phép | ✅ | ✅ | OPTIONS /api/users |
Idempotent nghĩa là gọi cùng một request nhiều lần cho kết quả giống như gọi một lần.
DELETE /api/users/42gọi 5 lần vẫn chỉ xóa user 42 — lần sau trả 404 cũng được, không tạo tác dụng phụ mới.
Ví dụ thực tế: CRUD với REST
Giả sử bạn xây API quản lý user:
# Lấy danh sách users
GET /api/users
# Lấy user có id = 42
GET /api/users/42
# Tạo user mới
POST /api/users
Content-Type: application/json
{
"name": "Nguyen Van A",
"email": "a@example.com"
}
# Cập nhật toàn bộ user 42 (thiếu field nào là mất field đó)
PUT /api/users/42
Content-Type: application/json
{
"name": "Nguyen Van B",
"email": "b@example.com"
}
# Cập nhật một phần: chỉ đổi tên
PATCH /api/users/42
Content-Type: application/json
{
"name": "Nguyen Van C"
}
# Xóa user 42
DELETE /api/users/42
Lưu ý quan trọng: PUT thay thế toàn bộ tài nguyên; nếu client quên gửi email trong ví dụ trên, email sẽ bị xóa sạch. PATCH chỉ thay đổi đúng field được gửi — an toàn hơn cho cập nhật từng phần.
HTTP Status Codes — “Ngôn ngữ” trạng thái
Status codes là cách server trả lời “chuyện gì đã xảy ra” cho client. Dùng đúng status code giúp client xử lý tự động mà không cần parse body.
2xx — Thành công
| Code | Ý nghĩa | Khi nào dùng |
|---|---|---|
200 OK | Thành công | GET, PUT, PATCH thành công |
201 Created | Đã tạo | POST tạo tài nguyên mới — kèm Location header trỏ tới resource |
202 Accepted | Đã nhận, xử lý sau | Task bất đồng bộ (job queue) |
204 No Content | Thành công, không có body | DELETE thành công |
Ví dụ response chuẩn khi tạo user:
HTTP/1.1 201 Created
Location: /api/users/43
Content-Type: application/json
{
"id": 43,
"name": "Nguyen Van A",
"email": "a@example.com",
"createdAt": "2026-09-07T10:00:00Z"
}
3xx — Chuyển hướng
| Code | Ý nghĩa |
|---|---|
301 Moved Permanently | Tài nguyên đổi URL vĩnh viễn |
302 Found | Tạm thời chuyển hướng |
304 Not Modified | Client có bản cache còn dùng được (kết hợp ETag) |
4xx — Lỗi phía client
| Code | Ý nghĩa | Khi nào dùng |
|---|---|---|
400 Bad Request | Request sai cú pháp, thiếu field bắt buộc | JSON hỏng, query sai |
401 Unauthorized | Chưa xác thực | Thiếu/malformed token |
403 Forbidden | Không có quyền truy cập | Đã đăng nhập nhưng không phải admin |
404 Not Found | Tài nguyên không tồn tại | Sai URL, sai id |
405 Method Not Allowed | Method không được hỗ trợ | DELETE /api/users khi chỉ cho GET/POST |
409 Conflict | Xung đột với trạng thái hiện tại | Email đã tồn tại, version conflict |
422 Unprocessable Entity | Dữ liệu hợp lệ về cú pháp nhưng fail validation | Email sai định dạng |
5xx — Lỗi phía server
| Code | Ý nghĩa |
|---|---|
500 Internal Server Error | Lỗi không xác định — bug trên server |
502 Bad Gateway | Server nhận response không hợp lệ từ upstream |
503 Service Unavailable | Server quá tải hoặc đang bảo trì |
Thiết kế error response thống nhất
Một API tốt phải trả lỗi có cấu trúc nhất quán để client dễ xử lý:
{
"error": {
"code": "EMAIL_EXISTS",
"message": "Email đã được sử dụng bởi tài khoản khác",
"details": [
{ "field": "email", "message": "Email a@example.com đã tồn tại" }
]
}
}
Thay vì trả lỗi kiểu tự do:
{ "err": "duplicate key value violates unique constraint..." }
Thiết kế URL (Resource Naming) chuẩn
URL là “danh từ” của REST — nó định danh tài nguyên, không phải hành động.
✅ Nên làm
- Dùng danh từ số nhiều:
/api/users,/api/posts, không phải/api/getUsers - Lồng nhau khi có quan hệ rõ ràng:
/api/users/42/posts(bài viết của user 42) - Dùng kebab-case hoặc snake_case:
/api/user-profileshoặc/api/user_profiles - Tài nguyên được định danh bằng id:
/api/users/42 - Hành động tách riêng hoặc dùng sub-resource:
POST /api/users/42/avatarthay vìPOST /api/uploadAvatar
❌ Tránh
- Động từ trong URL:
/api/getUser,/api/deletePost,/api/createOrder - Viết hoa lẫn lộn:
/api/UserProfiles - Quá nhiều cấp nesting:
/api/users/42/posts/7/comments/9(tối đa 2 cấp)
Filtering, Sorting, Pagination — dùng query params
# Lọc theo trạng thái và tìm kiếm
GET /api/users?status=active&search=nguyen
# Sắp xếp
GET /api/users?sort=createdAt&order=desc
# Phân trang kiểu page/limit (phổ biến)
GET /api/users?page=2&limit=20
# Phân trang kiểu cursor (dữ liệu lớn, hay thay đổi)
GET /api/users?cursor=eyJpZCI6MTAwMH0&limit=20
Response phân trang nên chứa metadata đầy đủ:
{
"data": [
{ "id": 21, "name": "Nguyen Van A" },
{ "id": 22, "name": "Tran Thi B" }
],
"pagination": {
"page": 2,
"limit": 20,
"total": 154,
"totalPages": 8,
"hasNextPage": true,
"nextCursor": "eyJpZCI6NDJ9"
}
}
API Versioning — Quản lý thay đổi
API sẽ thay đổi theo thời gian; khi thay đổi phá vỡ tương thích (đổi response format, xóa field…), bạn phải version để client cũ không bị vỡ.
Cách phổ biến nhất: version trong URL path
GET /api/v1/users
GET /api/v2/users
Ưu điểm: cực kỳ rõ ràng, dễ triển khai trên gateway, client biết ngay mình đang dùng version nào.
Cách khác ít phổ biến hơn
# Version qua header (media type versioning)
GET /api/users
Accept: application/vnd.devs2.api+json;version=2
# Version qua query param
GET /api/users?api-version=2
Quy tắc vàng: Version ngay từ đầu (lúc API “sinh ra” hãy gọi là
v1), không bao gip phá vỡ contract cũ mà không deprecate trước, và luôn giữ song song tối thiểu một phiên bản cũ với thời gian chuyển tiếp rõ ràng.
Nội dung request/response
Luôn luôn dùng JSON (và khai báo đúng Content-Type)
POST /api/users
Content-Type: application/json
Accept: application/json
Field naming nhất quán
Chọn một quy ước và tuân thủ nghiêm ngặt — snake_case (như GitHub, Stripe) hoặc camelCase (như Google). Trộn lẫn là ác mộng cho client.
{
"user_id": 42,
"created_at": "2026-09-07T10:00:00Z"
}
Ngày giờ luôn dùng ISO 8601 với timezone
2026-09-07T10:00:00Z ✅
2026-09-07 10:00:00 ❌ (mơ hồ timezone)
Authentication & Authorization
REST là stateless, nên mọi request cần tự xác thực. Ba cách phổ biến:
1. API Key — đơn giản nhất
GET /api/v1/weather?city=hanoi
X-API-Key: abc123xyz
Phù hợp: service-to-service, dữ liệu công khai, cần kiểm soát quota.
2. JWT (JSON Web Token) — phổ biến cho web app
GET /api/v1/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsIm5hbWUiOiJOZ3V5ZW4gVmFuIEEiLCJpYXQiOjE3NTcyMDAwMDB9...
Phù hợp: frontend app (React, Vue…) gọi API. Nên dùng access token thời hạn ngắn (15-60 phút) kèm refresh token để lấy token mới.
3. OAuth 2.0 — chuẩn ủy quyền cho bên thứ ba
Phù hợp: “Login with Google/GitHub”, API cho đối tác bên ngoài. Gồm các flow: Authorization Code, Client Credentials, PKCE.
Nguyên tắc: luôn dùng HTTPS, không bao giờ đặt token/API key trong URL query (dễ lọt vào log), và token phải có thời hạn (expiry).
Bảo mật REST API
Ngoài xác thực, một REST API an toàn cần:
Rate limiting — chống abuse
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{ "error": { "code": "RATE_LIMITED", "message": "Quá nhiều request. Thử lại sau 60 giây." } }
Các header chuẩn: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
CORS — kiểm soát ai được gọi API từ trình duyệt
Access-Control-Allow-Origin: https://devs2.org
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Chống OWASP Top 10 cơ bản
- Broken Object Level Authorization (IDOR): luôn kiểm tra user có quyền truy cập tài nguyên cụ thể, không chỉ endpoint.
GET /api/users/42phải kiểm tra “bạn” có phải user 42 hoặc admin không. - Mass Assignment: không cho client gửi field nguy hiểm (
role: "admin",isPaid: true). Dùng whitelist field khi update. - Input validation: validate mọi input từ client ở server — không bao giờ tin client.
- Không lộ thông tin nhạy cảm trong error message (stack trace, SQL query).
Best Practices Checklist
Trước khi “ship” một REST API, hãy kiểm tra nhanh:
- Dùng danh từ số nhiều cho resource, không lẫn động từ trong URL
- GET/POST/PUT/PATCH/DELETE đúng ngữ nghĩa, PUT/DELETE idempotent
- Status codes đúng 2xx/4xx/5xx, không trả
200cho mọi trường hợp - Error response cấu trúc thống nhất với mã lỗi riêng
- Phân trang + filter + sort qua query params, kèm metadata
- Version API từ ngày đầu (
/api/v1/...) - JSON +
Content-Typeđúng, field naming nhất quán, ngày giờ ISO 8601 - Xác thực rõ ràng (API key / JWT / OAuth), HTTPS bắt buộc
- Rate limiting + CORS cấu hình đúng
- Kiểm tra quyền ở mức object (chống IDOR), whitelist input
- Tài liệu hóa API (OpenAPI/Swagger)
Kết luận
REST API không phải công nghệ cao siêu — nó là cách tận dụng HTTP một cách thông minh và nhất quán. Điều làm nên một API “đẹp” không nằm ở framework hay ngôn ngữ, mà ở sự nhất quán: nhất quán về cách đặt tên URL, cách trả status code, cách báo lỗi, cách phân trang.
Hãy bắt đầu từ những nguyên tắc nhỏ: dùng đúng HTTP method, trả đúng status code, thiết kế URL như danh từ, và luôn nghĩ đến người dùng API của bạn — chính là các frontend developer (hoặc chính bạn) đang cần dữ liệu một cách dễ đoán và dễ debug nhất.
Tóm tắt nhanh
- REST = tận dụng chuẩn HTTP để thiết kế API tài nguyên
- HTTP methods là động từ, URL là danh từ, status codes là trạng thái
- Stateless + JSON + HTTPS là nền tảng của mọi REST API hiện đại
- Versioning, pagination, error format chuẩn biến API “chạy được” thành API “chuyên nghiệp”
- Bảo mật object-level (IDOR), rate limiting và validate input là tối thiểu bắt buộc
Bài viết tiếp theo: Bảo mật API nâng cao — JWT, Refresh Token và kiểm soát quyền chi tiết (RBAC/ABAC).