TÓM TẮT
Tên tài nguyên của API REST nên dùng dạng số nhiều. Sử dụng /pets/{id} chứ không phải /pet/{id}. Tên số nhiều đại diện cho các tập hợp một cách nhất quán, phù hợp với ngữ nghĩa HTTP và cách các nhà phát triển tư duy về tài nguyên. PetstoreAPI hiện đại sử dụng tên số nhiều xuyên suốt thiết kế API của mình, tuân thủ các thực tiễn tốt nhất trong ngành.
Giới thiệu
Bạn đang thiết kế một API REST. Bạn cần một điểm cuối để lấy thông tin người dùng theo ID. Bạn sẽ sử dụng /user/123 hay /users/123? Câu hỏi này đã gây ra vô số cuộc tranh luận, các chủ đề trên Stack Overflow và các cuộc cãi vã trong nhóm.
Câu trả lời rõ ràng là: dùng số nhiều. Nhưng việc hiểu tại sao lại quan trọng hơn việc ghi nhớ quy tắc. Lý do liên quan đến cách REST hoạt động, cách các tập hợp hành xử và cách các nhà phát triển tư duy về tài nguyên.
Swagger Petstore cũ đã làm sai điều này, sử dụng /pet/{id} thay vì /pets/{id}. Sự không nhất quán này đã dạy hàng triệu nhà phát triển một mẫu hình sai. PetstoreAPI hiện đại khắc phục điều này bằng cách sử dụng tên số nhiều một cách nhất quán trên tất cả các điểm cuối.
Trong hướng dẫn này, bạn sẽ tìm hiểu lý do tại sao tên số nhiều là lựa chọn đúng đắn, cách chúng phù hợp với các nguyên tắc REST và cách triển khai chúng một cách chính xác bằng cách sử dụng PetstoreAPI hiện đại làm tài liệu tham khảo.
Cuộc tranh luận giữa số nhiều và số ít
Cuộc tranh luận tồn tại vì cả hai cách tiếp cận đều có vẻ hợp lý thoạt nhìn.
Luận điểm ủng hộ số ít
“Khi tôi yêu cầu /user/123, tôi nhận được một người dùng, không phải nhiều người dùng. Số ít là hợp lý.”
Lý do này tập trung vào phản hồi—bạn đang nhận được một tài nguyên duy nhất, vì vậy URL nên ở dạng số ít.
Luận điểm ủng hộ số nhiều
“URL đại diện cho một tập hợp. /users là tập hợp tất cả người dùng. /users/123 là mục 123 trong tập hợp đó.”
Lý do này tập trung vào cấu trúc tài nguyên—URL đại diện cho các tập hợp, và bạn đang truy cập các mục bên trong các tập hợp đó.
Tại sao điều này lại quan trọng
Lựa chọn của bạn ảnh hưởng đến:
- Tính nhất quán của API - Việc đặt tên hỗn tạp gây nhầm lẫn cho các nhà phát triển
- Mô hình tư duy - Cách các nhà phát triển hiểu cấu trúc API của bạn
- Sinh mã - Các công cụ tạo mã client dựa trên tên tài nguyên
- Rõ ràng tài liệu - Tài liệu cần giải thích logic đặt tên của bạn
Tại sao tên số nhiều chiếm ưu thế
Tên tài nguyên số nhiều phù hợp với các nguyên tắc REST và ngữ nghĩa HTTP. Đây là lý do.
1. Các tập hợp là số nhiều
Trong REST, tài nguyên là các tập hợp. Khi bạn truy cập /users, bạn đang truy cập tập hợp người dùng. Khi bạn truy cập /users/123, bạn đang truy cập mục 123 trong tập hợp người dùng đó.
GET /users ← Tập hợp người dùng
GET /users/123 ← Mục 123 trong tập hợp người dùng
POST /users ← Thêm vào tập hợp người dùng
DELETE /users/123 ← Xóa mục 123 khỏi tập hợp người dùng
Mô hình tư duy này nhất quán. Tập hợp luôn là /users, cho dù bạn đang truy cập tất cả các mục hay một mục.
Với tên số ít, mô hình tư duy bị phá vỡ:
GET /user ← Người dùng nào?
GET /user/123 ← Điều này có lý
POST /user ← Thêm vào... cái gì?
2. Các phương thức HTTP hoạt động trên các tập hợp
Các phương thức HTTP mô tả các thao tác trên các tập hợp:
GET /users- Truy xuất tập hợpPOST /users- Thêm vào tập hợpGET /users/123- Truy xuất mục 123 từ tập hợpPUT /users/123- Thay thế mục 123 trong tập hợpDELETE /users/123- Xóa mục 123 khỏi tập hợp
Tập hợp là tài nguyên. Các mục riêng lẻ là thành viên của tập hợp đó.
3. Tính nhất quán trên các điểm cuối
Tên số nhiều tạo ra sự nhất quán:
GET /pets ← Tập hợp
GET /pets/123 ← Mục trong tập hợp
GET /orders ← Tập hợp
GET /orders/456 ← Mục trong tập hợp
Tên số ít buộc bạn phải chuyển đổi giữa số ít và số nhiều:
GET /pet ← Không có ý nghĩa
GET /pet/123 ← Có ý nghĩa
GET /pets ← Khoan đã, bây giờ lại là số nhiều?
4. Tiêu chuẩn ngành
Các API lớn sử dụng tên số nhiều:
- API GitHub:
/repos,/users,/issues - API Stripe:
/customers,/charges,/subscriptions - API Twilio:
/accounts,/messages,/calls - API Google:
/users,/groups,/files
PetstoreAPI hiện đại tuân theo tiêu chuẩn này với /pets, /orders, /users.
Mô hình tư duy về tập hợp
Hiểu về các tập hợp giúp bạn thiết kế API tốt hơn.
Các tập hợp trong REST
Một tập hợp là một tập hợp các tài nguyên. Trong một API cửa hàng thú cưng:
/pets- Tập hợp tất cả thú cưng/orders- Tập hợp tất cả đơn hàng/users- Tập hợp tất cả người dùng
Mỗi tập hợp hỗ trợ các thao tác:
GET /pets ← Liệt kê thú cưng (có lọc, phân trang)
POST /pets ← Tạo một thú cưng mới
GET /pets/{id} ← Lấy một thú cưng cụ thể
PUT /pets/{id} ← Cập nhật một thú cưng cụ thể
DELETE /pets/{id} ← Xóa một thú cưng cụ thể
Các tập hợp con
Các tập hợp có thể chứa các tập hợp con:
GET /pets/{id}/photos ← Tập hợp ảnh cho thú cưng {id}
POST /pets/{id}/photos ← Thêm ảnh cho thú cưng {id}
GET /pets/{id}/photos/{photoId} ← Ảnh cụ thể
Mẫu hình vẫn nhất quán: các tập hợp là số nhiều, các mục được truy cập bằng ID.
Ví dụ về PetstoreAPI hiện đại
PetstoreAPI hiện đại triển khai điều này một cách chính xác:
GET /pets
GET /pets/{petId}
GET /pets/{petId}/photos
POST /pets/{petId}/vaccinations
GET /orders
GET /orders/{orderId}
GET /orders/{orderId}/items
Mọi tập hợp đều là số nhiều. Mọi truy cập mục đều sử dụng {id} trong tập hợp đó.
Cách PetstoreAPI hiện đại sử dụng tên số nhiều
Hãy cùng xem các ví dụ thực tế từ PetstoreAPI hiện đại.
Tài nguyên thú cưng
GET /pets ← Liệt kê tất cả thú cưng
POST /pets ← Tạo một thú cưng mới
GET /pets/{petId} ← Lấy thú cưng cụ thể
PUT /pets/{petId} ← Cập nhật thú cưng
DELETE /pets/{petId} ← Xóa thú cưng
GET /pets?status=AVAILABLE ← Lọc thú cưng theo trạng thái
Tài nguyên đơn hàng
GET /orders ← Liệt kê tất cả đơn hàng
POST /orders ← Tạo đơn hàng
GET /orders/{orderId} ← Lấy đơn hàng cụ thể
PUT /orders/{orderId} ← Cập nhật đơn hàng
DELETE /orders/{orderId} ← Hủy đơn hàng
Tài nguyên người dùng
GET /users ← Liệt kê người dùng
POST /users ← Tạo người dùng
GET /users/{userId} ← Lấy người dùng cụ thể
PUT /users/{userId} ← Cập nhật người dùng
DELETE /users/{userId} ← Xóa người dùng
Tài nguyên lồng nhau
GET /pets/{petId}/photos ← Ảnh của thú cưng
POST /pets/{petId}/photos ← Thêm ảnh
GET /pets/{petId}/vaccinations ← Tiêm chủng của thú cưng
POST /pets/{petId}/vaccinations ← Ghi lại tiêm chủng
GET /orders/{orderId}/items ← Các mục của đơn hàng
Kiểm tra tài liệu API REST đầy đủ để có danh sách điểm cuối hoàn chỉnh.
Các luận điểm phổ biến ủng hộ số ít (và tại sao chúng sai)
Hãy cùng xem xét các luận điểm phổ biến ủng hộ tên số ít.
Luận điểm 1: “Phản hồi là số ít”
Luận điểm: “Khi tôi GET /user/123, tôi nhận được một người dùng. Số ít là hợp lý.”
Phản biện: URL đại diện cho vị trí tài nguyên, không phải phản hồi. /users/123 có nghĩa là “mục 123 trong tập hợp người dùng.” Việc phản hồi là số ít không thay đổi cấu trúc tập hợp.
Luận điểm 2: “Đọc trong code dễ hơn”
Luận điểm: “getUser(id) đọc dễ hiểu hơn getUsers(id).”
Phản biện: Việc đặt tên mã client của bạn độc lập với cấu trúc URL. Bạn có thể có:
// URL: GET /users/123
function getUser(id) {
return api.get(`/users/${id}`);
}
Tên hàm không cần phải khớp với URL.
Luận điểm 3: “Số ít tránh được các vấn đề ngữ pháp”
Luận điểm: “Còn các tài nguyên như ‘status’ (trạng thái) hoặc ‘information’ (thông tin) không có dạng số nhiều rõ ràng thì sao?”
Phản biện: Đây thường là các tài nguyên đơn thể (singleton), không phải tập hợp. Sử dụng số ít cho các đơn thể:
GET /status ← Trạng thái hệ thống (đơn thể)
GET /configuration ← Cấu hình ứng dụng (đơn thể)
GET /users ← Tập hợp người dùng (số nhiều)
Luận điểm 4: “ORM của tôi sử dụng tên bảng số ít”
Luận điểm: “Các bảng cơ sở dữ liệu của tôi là số ít (user, order), vì vậy API của tôi cũng nên khớp.”
Phản biện: Thiết kế API của bạn không nên để lộ các chi tiết triển khai cơ sở dữ liệu. API REST đại diện cho các tài nguyên, không phải các bảng cơ sở dữ liệu. Sử dụng số nhiều cho các tập hợp bất kể lược đồ cơ sở dữ liệu của bạn.
Kiểm thử đặt tên tài nguyên với Apidog
Apidog giúp bạn xác thực và kiểm thử các quy ước đặt tên tài nguyên.
Nhập PetstoreAPI hiện đại
- Nhập đặc tả OpenAPI của PetstoreAPI hiện đại
- Apidog tự động phát hiện các mẫu tài nguyên
- Xem xét đặt tên điểm cuối để đảm bảo tính nhất quán
Tạo các bài kiểm thử quy ước đặt tên
// Script kiểm thử của Apidog
pm.test("Tên tài nguyên là số nhiều", function() {
const path = pm.request.url.getPath();
const segments = path.split('/').filter(s => s);
// Kiểm tra phân đoạn đầu tiên là số nhiều
const resource = segments[0];
pm.expect(resource).to.match(/s$/); // Kết thúc bằng 's'
});
Xác thực tính nhất quán
Apidog có thể kiểm tra:
- Tất cả các điểm cuối tập hợp đều sử dụng tên số nhiều
- Các tài nguyên con tuân theo cùng một mẫu
- Không trộn lẫn số ít/số nhiều trong cùng một API
Kiểm thử với các yêu cầu thực tế
GET https://api.petstoreapi.com/v1/pets
GET https://api.petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24
GET https://api.petstoreapi.com/v1/orders
Apidog xác thực các phản hồi và giúp bạn đảm bảo tính nhất quán trong việc đặt tên trên toàn bộ API của bạn.
Các trường hợp đặc biệt và ngoại lệ
Một số tài nguyên không phù hợp với mẫu số nhiều.
Tài nguyên đơn thể
Các tài nguyên chỉ tồn tại một lần nên là số ít:
GET /status ← Trạng thái hệ thống
GET /configuration ← Cấu hình ứng dụng
GET /health ← Kiểm tra tình trạng
GET /metrics ← Các chỉ số hệ thống
Đây không phải là các tập hợp, vì vậy không áp dụng số nhiều.
Tài nguyên điều khiển (Controller)
Các hành động không phù hợp với các thao tác CRUD:
POST /login ← Hành động xác thực
POST /logout ← Kết thúc phiên
POST /search ← Thao tác tìm kiếm phức tạp
Đây là những ngoại lệ có thể chấp nhận được vì chúng đại diện cho các hành động, không phải tài nguyên.
Danh từ không đếm được
Một số danh từ không có dạng số nhiều rõ ràng:
GET /information ← Số ít (không đếm được)
GET /data ← Số ít (không đếm được)
GET /equipment ← Số ít (không đếm được)
Sử dụng số ít cho các danh từ không đếm được, nhưng những trường hợp này hiếm gặp trong các API thông thường.
Cách tiếp cận của PetstoreAPI hiện đại
PetstoreAPI hiện đại xử lý các trường hợp này:
# Các tập hợp (số nhiều)
GET /pets
GET /orders
GET /users
# Các đơn thể (số ít)
GET /health
GET /metrics
# Các hành động (động từ số ít)
POST /login
POST /logout
Kết luận
Tên tài nguyên của API REST nên là số nhiều. Điều này phù hợp với ngữ nghĩa của tập hợp, các phương thức HTTP và tiêu chuẩn ngành. PetstoreAPI hiện đại thể hiện mẫu hình này một cách chính xác trên tất cả các điểm cuối.
Những điểm chính cần nhớ:
- Sử dụng tên số nhiều cho các tập hợp (
/pets,/orders,/users) - Các mục riêng lẻ được truy cập trong các tập hợp (
/pets/123) - Các tài nguyên đơn thể có thể là số ít (
/status,/health) - Tính nhất quán quan trọng hơn sự hoàn hảo
- Kiểm thử các quy ước đặt tên của bạn với Apidog
Cuộc tranh luận giữa số nhiều và số ít đã được giải quyết. Hãy tuân theo tiêu chuẩn ngành, sử dụng tên số nhiều và xây dựng các API mà các nhà phát triển hiểu một cách trực quan.
Các bước tiếp theo:
- Xem xét các điểm cuối API của bạn để đảm bảo tính nhất quán trong đặt tên
- Kiểm tra tài liệu PetstoreAPI hiện đại để tham khảo các mẫu
- Sử dụng Apidog để xác thực thiết kế API của bạn
- Cập nhật đặc tả OpenAPI của bạn với tên tài nguyên số nhiều
Câu hỏi thường gặp
Tôi có nên thay đổi API hiện có của mình từ số ít sang số nhiều không?
Nếu API của bạn đã đi vào sản xuất, việc thay đổi tên tài nguyên là một thay đổi gây phá vỡ. Hãy cân nhắc:
- Thêm các điểm cuối v2 mới với tên số nhiều
- Duy trì tương thích ngược bằng cách chuyển hướng
- Tài liệu hóa rõ ràng quy ước đặt tên
Đừng làm hỏng các client hiện có chỉ vì tính nhất quán trong đặt tên.
Còn những tài nguyên vốn đã là số nhiều thì sao?
Nếu tên tài nguyên vốn đã là số nhiều một cách tự nhiên (như “analytics” hoặc “series”), hãy giữ nguyên:
GET /analytics ← Vốn đã là số nhiều
GET /series ← Vốn đã là số nhiều
GET /species ← Vốn đã là số nhiều
Tôi xử lý tài nguyên lồng nhau như thế nào?
Giữ cả hai cấp độ ở dạng số nhiều:
GET /users/{userId}/orders ← Cả hai đều số nhiều
GET /pets/{petId}/vaccinations ← Cả hai đều số nhiều
GET /orders/{orderId}/items ← Cả hai đều số nhiều
Điều gì sẽ xảy ra nếu nhóm của tôi thích số ít hơn?
Tính nhất quán trong API của bạn là quan trọng nhất. Nếu nhóm của bạn đã chuẩn hóa trên tên số ít và việc thay đổi sẽ gây nhầm lẫn, hãy giữ nguyên số ít. Nhưng đối với các API mới, hãy sử dụng số nhiều.
GraphQL sử dụng số nhiều hay số ít?
GraphQL thường sử dụng số ít cho các truy vấn một mục và số nhiều cho các danh sách:
query {
user(id: "123") { ... } # Số ít
users(limit: 10) { ... } # Số nhiều
}
Điều này khác với REST vì các truy vấn GraphQL rõ ràng về việc trả về một hay nhiều.
PetstoreAPI hiện đại xử lý vấn đề này như thế nào?
PetstoreAPI hiện đại sử dụng tên số nhiều một cách nhất quán trên tất cả các điểm cuối REST. Kiểm tra hướng dẫn API REST để biết các ví dụ đầy đủ.
Tôi có thể kiểm thử các quy ước đặt tên một cách tự động không?
Có, Apidog có thể chạy các bài kiểm thử tự động để kiểm tra các mẫu đặt tên tài nguyên trên toàn bộ API của bạn. Nhập đặc tả OpenAPI của bạn và tạo các trường hợp kiểm thử cho các quy ước đặt tên.
Còn các API không phải tiếng Anh thì sao?
Quy tắc số nhiều áp dụng bất kể ngôn ngữ. Nếu API của bạn sử dụng tên tài nguyên tiếng Pháp, hãy dùng số nhiều tiếng Pháp. Nếu sử dụng tiếng Nhật, hãy tuân theo các quy tắc ngữ pháp tiếng Nhật. Nguyên tắc (các tập hợp là số nhiều) vẫn giữ nguyên.
