Skip to main content
API 9 mins read

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.

#REST API #HTTP #Backend #API Design #Web Development #JSON #Status Codes #Authentication #Best Practices

Minh họa REST API với HTTP methods và status codes

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:

MethodChức năngIdempotent?An toàn?Ví dụ
GETLấy dữ liệu✅✅GET /api/users
POSTTạo tài nguyên mới❌❌POST /api/users
PUTThay thế toàn bộ tài nguyên✅❌PUT /api/users/42
PATCHCập nhật một phần❌❌PATCH /api/users/42
DELETEXóa tài nguyên✅❌DELETE /api/users/42
HEADLấy header giống GET, không body✅✅HEAD /api/users
OPTIONSMô 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/42 gọ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ĩaKhi nào dùng
200 OKThành côngGET, PUT, PATCH thành công
201 CreatedĐã tạoPOST tạo tài nguyên mới — kèm Location header trỏ tới resource
202 AcceptedĐã nhận, xử lý sauTask bất đồng bộ (job queue)
204 No ContentThành công, không có bodyDELETE 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 PermanentlyTài nguyên đổi URL vĩnh viễn
302 FoundTạm thời chuyển hướng
304 Not ModifiedClient có bản cache còn dùng được (kết hợp ETag)

4xx — Lỗi phía client

CodeÝ nghĩaKhi nào dùng
400 Bad RequestRequest sai cú pháp, thiếu field bắt buộcJSON hỏng, query sai
401 UnauthorizedChưa xác thựcThiếu/malformed token
403 ForbiddenKhông có quyền truy cậpĐã đăng nhập nhưng không phải admin
404 Not FoundTài nguyên không tồn tạiSai URL, sai id
405 Method Not AllowedMethod không được hỗ trợDELETE /api/users khi chỉ cho GET/POST
409 ConflictXung đột với trạng thái hiện tạiEmail đã tồn tại, version conflict
422 Unprocessable EntityDữ liệu hợp lệ về cú pháp nhưng fail validationEmail sai định dạng

5xx — Lỗi phía server

CodeÝ nghĩa
500 Internal Server ErrorLỗi không xác định — bug trên server
502 Bad GatewayServer nhận response không hợp lệ từ upstream
503 Service UnavailableServer 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-profiles hoặ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/avatar thay 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/42 phả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ả 200 cho 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).

Recently Used Tools