Cách xây dựng REST API: thiết kế, bảo mật và triển khai
Để xây dựng REST API, hãy liệt kê các tài nguyên mà ứng dụng quản lý (người dùng, đơn hàng, lịch đặt), gán cho mỗi tài nguyên một URL như /orders và /orders/{id}, rồi dùng phương thức HTTP cho các thao tác: GET để đọc, POST để tạo mới, PATCH để cập nhật, DELETE để xóa. Trả về JSON với các mã trạng thái có ý nghĩa, kiểm tra mọi dữ liệu đầu vào, yêu cầu xác thực và kiểm tra quyền truy cập từng bản ghi trên máy chủ, và phân trang các danh sách. Sau đó hãy viết tài liệu cho các endpoint và triển khai API phía sau HTTPS.
Hướng dẫn này đề cập đến các quyết định thiết kế, một bộ đường dẫn mẫu, prompt cho công cụ xây dựng ứng dụng bằng AI, và những lỗi thường gây ra lỗ hổng bảo mật. Nếu API còn mới với bạn, hãy bắt đầu với API là gì.
Khi nào bạn cần REST API
- Giao diện web cần lưu và tải dữ liệu từ máy chủ
- Ứng dụng di động, đối tác hoặc công cụ tự động hóa cần truy cập dữ liệu của bạn
- Các dịch vụ khác gửi sự kiện đến bạn (webhook)
- Bạn đang chia việc giữa đội frontend và đội backend
REST là kiểu phổ biến nhất nhưng không phải kiểu duy nhất. REST và GraphQL giải thích khi nào một endpoint truy vấn linh hoạt duy nhất phù hợp hơn.
Thiết kế trước: tài nguyên và đường dẫn
Hãy viết ra các danh từ trong ứng dụng và những việc người dùng làm với chúng. Với một ứng dụng đặt lịch đơn giản:
| Phương thức | Đường dẫn | Chức năng | Mã thành công |
|---|---|---|---|
GET | /api/bookings | Liệt kê lịch đặt của người gọi (có phân trang) | 200 |
POST | /api/bookings | Tạo lịch đặt | 201 |
GET | /api/bookings/{id} | Lấy một lịch đặt | 200 |
PATCH | /api/bookings/{id} | Thay đổi một số trường | 200 |
DELETE | /api/bookings/{id} | Hủy lịch đặt | 204 |
GET | /api/health | Kiểm tra tình trạng cho hệ thống giám sát | 200 |
Các thao tác này tương ứng với tạo, đọc, cập nhật và xóa; xem CRUD là gì. Một số quy ước nên tuân theo:
- Danh từ số nhiều, không dùng động từ trong URL:
/bookings, không phải/getBookings. - Chỉ lồng một cấp khi điều đó làm rõ quyền sở hữu:
/bookings/{id}/notes. - Các hành động không thuộc CRUD có thể là tài nguyên con:
POST /bookings/{id}/cancelrõ ràng hơn một PATCH "thần kỳ". - Đặt tên nhất quán cho các trường, chẳng hạn
created_atở mọi nơi.
Mã trạng thái và lỗi
Hãy dùng các mã HTTP chuẩn để client biết chuyện gì đã xảy ra mà không cần phân tích văn bản:
| Mã | Ý nghĩa | Dùng khi |
|---|---|---|
| 200 | OK | Đọc hoặc cập nhật thành công |
| 201 | Created | Một yêu cầu POST đã tạo ra thứ gì đó |
| 204 | No Content | Thành công và không có gì để trả về |
| 400 | Bad Request | Dữ liệu đầu vào không qua kiểm tra |
| 401 | Unauthorized | Chưa đăng nhập hoặc token không hợp lệ |
| 403 | Forbidden | Đã đăng nhập nhưng không có quyền |
| 404 | Not Found | Không tồn tại, hoặc người gọi không được biết nó tồn tại |
| 409 | Conflict | Trùng lặp, hoặc khung giờ đã được đặt |
| 429 | Too Many Requests | Đã vượt giới hạn số lượt yêu cầu |
| 500 | Server Error | Có lỗi xảy ra ở phía bạn |
Trả về lỗi theo một cấu trúc JSON nhất quán, ví dụ {"error": {"code": "slot_taken", "message": "Khung giờ đó không còn trống."}}, và tuyệt đối không đưa stack trace hay lỗi cơ sở dữ liệu vào phản hồi.
Lựa chọn và đánh đổi
| Quyết định | Lựa chọn đơn giản | Phương án thay thế |
|---|---|---|
| API nằm ở đâu | API route trong framework web của bạn | Một dịch vụ API riêng, hữu ích khi có nhiều client hoặc cần ngôn ngữ khác |
| Xác thực | Cookie phiên cho ứng dụng web của bạn | Token (bearer token hoặc API key) cho ứng dụng di động và bên thứ ba |
| Phân trang | ?page=2&limit=20 | Dựa trên con trỏ (?after=...), ổn định hơn với danh sách lớn, thay đổi liên tục |
| Phiên bản | Không có cho đến khi có người dùng bên ngoài | /v1/ trong đường dẫn khi đã có người khác phụ thuộc vào nó |
| Tài liệu | Một README liệt kê các đường dẫn | Đặc tả OpenAPI, từ đó các công cụ có thể tạo tài liệu tương tác và mã client |
Từng bước
- Liệt kê tài nguyên và đường dẫn như trên, bao gồm ai được gọi từng đường dẫn.
- Mô hình hóa dữ liệu trong cơ sở dữ liệu với các trường và quan hệ bạn cần.
- Xây dựng các đường dẫn đọc trước, sau đó đến tạo, cập nhật và xóa.
- Kiểm tra dữ liệu đầu vào ở mọi thao tác ghi bằng một thư viện schema: trường bắt buộc, kiểu dữ liệu, độ dài, giá trị cho phép. Từ chối các trường không xác định.
- Thêm xác thực, rồi đến phân quyền theo từng bản ghi: tải
/bookings/42phải kiểm tra rằng lịch đặt 42 thuộc về người gọi, không chỉ kiểm tra rằng ai đó đã đăng nhập. - Phân trang mọi danh sách và giới hạn kích thước trang tối đa.
- Giới hạn số lượt yêu cầu cho đăng nhập và các đường dẫn tốn tài nguyên. Xem giới hạn tần suất (rate limiting).
- Cấu hình CORS chỉ khi trình duyệt trên các tên miền khác phải gọi API, và liệt kê rõ các origin đó. Cách sửa lỗi CORS giải thích những lỗi bạn sẽ gặp.
- Viết tài liệu và kiểm thử cho từng đường dẫn, bao gồm cả các trường hợp lỗi.
- Triển khai với khóa bí mật trong biến môi trường, HTTPS, nhật ký và kiểm tra tình trạng.
Prompt cho công cụ xây dựng bằng AI
Tạo khung ban đầu:
Tạo một REST API cho lịch đặt với các đường dẫn sau: GET /api/health, GET /api/bookings (có phân trang, tối đa 50 mục mỗi trang), POST /api/bookings, GET /api/bookings/:id, PATCH /api/bookings/:id, DELETE /api/bookings/:id. Lưu dữ liệu trong cơ sở dữ liệu của chúng tôi. Kiểm tra thân yêu cầu bằng một thư viện schema và từ chối các trường không xác định. Trả về lỗi dạng JSON theo cấu trúc {"error": {"code", "message"}} với mã trạng thái đúng (400, 401, 403, 404, 409). Lưu các khóa bí mật trong biến môi trường.
Bảo mật:
Yêu cầu đăng nhập trên mọi đường dẫn của lịch đặt. Ở mọi thao tác đọc, cập nhật và xóa, kiểm tra trên máy chủ rằng lịch đặt thuộc về người dùng hiện tại; trả về 404 nếu không. Không bao giờ chấp nhận ID người dùng hay vai trò từ thân yêu cầu. Giới hạn POST /api/bookings ở 20 lần mỗi phút cho mỗi người dùng. Ghi lỗi vào nhật ký trên máy chủ mà không trả về stack trace.
Tài liệu:
Viết mô tả OpenAPI cho các đường dẫn này, và một README ngắn với ví dụ yêu cầu và phản hồi cho từng đường dẫn.
Kiểm thử API
Hãy kiểm thử từ bên ngoài frontend, vì kẻ tấn công cũng sẽ làm vậy:
- Mỗi đường dẫn hoạt động với dữ liệu hợp lệ và trả về đúng cấu trúc và mã đã được tài liệu hóa
- Thiếu hoặc sai trường dữ liệu trả về 400 kèm thông báo rõ ràng
- Không có token trả về 401 ở mọi đường dẫn được bảo vệ
- Người dùng A yêu cầu bản ghi của người dùng B theo ID nhận về 404 hoặc 403
- Danh sách được phân trang; giá trị
limitquá lớn bị giới hạn - Các yêu cầu tạo trùng lặp hoặc xung đột trả về 409, không phải 500
- Vượt giới hạn tần suất trả về 429
- Phản hồi lỗi không chứa stack trace, câu lệnh SQL hay khóa bí mật
- CORS chỉ cho phép các origin bạn chủ đích
Các lỗi thường gặp
- Kiểm tra đăng nhập nhưng không kiểm tra quyền sở hữu. Đây là lỗ hổng API phổ biến nhất: bất kỳ người dùng đã đăng nhập nào cũng có thể đọc mọi bản ghi chỉ bằng cách đổi ID.
- Tin tưởng client. Giá, vai trò và ID người dùng trong thân yêu cầu đều có thể bị chỉnh sửa.
- Trả về nguyên các dòng cơ sở dữ liệu. Mã băm mật khẩu và các trường nội bộ bị rò rỉ. Hãy chọn những gì mỗi phản hồi bao gồm.
- Danh sách không giới hạn. Một yêu cầu lấy toàn bộ bản ghi có thể làm chậm cả ứng dụng.
200 OKkèm thông báo lỗi bên trong. Client và hệ thống giám sát không thể biết là đã thất bại.- CORS cho phép tất cả trên một API dùng cookie.
- Không có kiểm tra tình trạng hay nhật ký, nên bạn chỉ biết có sự cố khi người dùng báo lại.
Để rà soát rộng hơn trước khi ra mắt, xem danh sách kiểm tra bảo mật cho ứng dụng xây dựng bằng AI.
Xây dựng REST API trên Mythex
Bạn có thể yêu cầu Mythex tạo một API như một phần của ứng dụng hoặc như một dịch vụ riêng. Công thức tài liệu REST API backend có một prompt khởi đầu: nêu rõ framework và các đường dẫn, yêu cầu lỗi JSON rõ ràng, lưu khóa bí mật trong biến môi trường, và kèm một Dockerfile. Các backend container viết bằng Node, Python, C#, Java và các ngôn ngữ khác được xuất bản qua Dockerfile, và Mythex xử lý việc triển khai từ Publish (API backend). Một dự án có thể chạy đồng thời một website và một máy chủ API, và bạn có thể chuyển đổi giữa chúng trong bản xem trước. Lưu khóa dưới dạng bí mật của dự án; nếu API cần cơ sở dữ liệu, hãy yêu cầu trong chat. Với các tác vụ định kỳ quanh API, xem cách chạy tác vụ nền.
Câu hỏi thường gặp
REST API là gì?
REST API là cách để các chương trình làm việc với dữ liệu của ứng dụng bạn qua HTTP. Mỗi loại dữ liệu là một tài nguyên có URL riêng, chẳng hạn /orders, và các phương thức chuẩn tác động lên nó: GET để đọc, POST để tạo mới, PATCH hoặc PUT để cập nhật, và DELETE để xóa. Dữ liệu thường được gửi dưới dạng JSON.
Tôi nên xây dựng REST API bằng ngôn ngữ nào?
Hãy dùng ngôn ngữ mà bạn hoặc đội của bạn có thể bảo trì. Node.js với Express hoặc Fastify, Python với FastAPI, và các framework C# hay Java đều hoạt động tốt. Các quy tắc thiết kế cho đường dẫn, mã trạng thái, kiểm tra dữ liệu và xác thực quan trọng hơn ngôn ngữ.
Làm sao để bảo mật REST API?
Yêu cầu xác thực trên mọi đường dẫn không công khai, kiểm tra trên máy chủ rằng người gọi được phép truy cập từng bản ghi cụ thể, kiểm tra toàn bộ dữ liệu đầu vào, dùng HTTPS, giới hạn số lượt yêu cầu, và lưu các khóa bí mật trong biến môi trường. Không bao giờ tin các ID hay vai trò do phía client gửi lên.
Có cần một backend riêng cho REST API không?
Không nhất thiết. Các framework như Next.js có thể phục vụ API route cùng với các trang. Dịch vụ API riêng sẽ hợp lý khi nhiều client (web, di động, đối tác) cùng dùng, hoặc khi API cần ngôn ngữ hay khả năng mở rộng riêng.