Một vài best practice khi xây dựng REST API

Khi xây dựng API, mọi người thông thường hay tập trung quá nhiều vào logic thực thi của API đấy, mà chưa để ý nhiều về mặt thiết kế API, vì đây là khía cạnh chính mà người sử dụng API họ quan tâm Và không chỉ vậy, với hệ thống microservices, thì một bản

Khi xây dựng API, mọi người thông thường hay tập trung quá nhiều vào logic thực thi của API đấy, mà chưa để ý nhiều về mặt thiết kế API, vì đây là khía cạnh chính mà người sử dụng API họ quan tâm

Và không chỉ vậy, với hệ thống microservices, thì một bản thiết kế API thống nhất là bắt buộc, giúp ích rất nhiều cho người sử dụng và người bảo trì sau này

1. Sử dụng snake_case hoặc kebab-case cho URL

VD, nếu muốn trả về danh sách system order

BAD

/systemOrders

GOOD

/system-orders hoặc /system_orders

2. Sử dụng camelCase hoặc snake_case cho parameter

VD, muốn trả về thông tin của 1 order

BAD

/system-orders/{OrderId}

GOOD

/system_orders/{orderId} hoặc /system_orders/{order_id}

3. Sử dụng số nhiều với Collection

Nếu muốn trả về danh sách user

BAD

GET /user or GET /User

GOOD

GET /users

4. Bỏ động từ ra khỏi URL của Resource

Không sử dụng động từ để mô tả ý định trong URL. Thay vào đó, sử dụng HTTP method để thể hiện

BAD

POST /updateuser/{userId} or GET /getusers

GOOD

PUT /users/{userId} # cập nhật user 
POST /users         # tạo mới user
GET /users/{userId} # trả về thông tin user

5. Sử dụng Động từ với URL không phải resource

Nếu bạn cần xây dựng một endpoint mà không trả về gì, chỉ thực hiện một hành động, thì bạn có thể sử dụng Động từ

VD, bạn muốn resend cảnh báo cho user

GOOD

POST /alerts/245743/resend

6. Thống nhất sử dụng camelCase hoặc snake_case cho thuộc tính JSON

Khi bạn cần xây dựng API với body request hoặc response là JSON, thì thuộc tính cần được thống nhất chỉ là camelCase hoặc snake_case

GOOD

{
   user_name: "Mohammad Faisal"
   user_id: "1"
}

hoặc

{
   userName: "Mohammad Faisal"
   userId: "1"
}

7. Monitoring

RESTful API phải thực hiện các API endpoint là /health, /{version} hoặc /metrics

/health

Response request /health với status code là 200 OK để kiểm tra API vẫn còn hoạt động

/{version}

Request đến endpoint /{version} để trả về số phiên bản API

/metrics

Cung cấp một vài số liệu mô tả về API như thời gian thực thi trung bình, rate limit của API, …

8. Sử dụng công cụ design API

Có nhiều công cụ thiết kế API tốt mà giúp tạo ra các tài liệu API rõ ràng như

API BlueprintSwagger

Với tài liệu API được mô tả chi tiết và đầy đủ thì sẽ cung cấp trải nghiệm rất tốt cho API của bạn

9. Sử dụng các con số thông thường cho version

Luôn luôn đặt version cho API, theo các phiên bản từ bé đến lớn, từ ít chức năng đến nhiều tính năng, VD v1, v2, …

GOOD

http://api.domain.com/v1/shops/3/products

Việc sử dụng version sẽ giúp cho việc thay đổi các endpoint sẽ không làm ảnh hưởng đến người dùng đang sử dụng hiện tại

10. Luôn thêm tổng số resource trong response

Nếu API trả về một danh sách object, cần phải thêm tổng số đối tượng trong response, và có thể trả thêm các thông tin pagination nữa

BAD

{
  users: [ 
     ...
  ]
}

GOOD

{
  users: [ 
     ...
  ],
  total: 34,
  page: 1, # optional
  per_page: 50 # optional
}

11. Luôn gửi Parameters limit và offset

Trong request GET danh sách resource, cần gửi thêm cả limitoffset, vì đây là các tham số hỗ trợ cho phân trang ở client

GOOD

GET /shops?offset=5&limit=5

12. Thêm tham số fields trong URL

Thêm tham số fields để chỉ trả về các trường cần thiết từ API

VD, khi chỉ muốn trả về name, contact, address của shop:

GET /shops?fields=id,name,address,contact

Nhờ vậy, sẽ giúp giảm bớt kích thước của response

13. Không truyền Authentication Token trong URL

Việc này thật là tệ hại khi để authen token trong URL, vì URL luôn được log lại trong trình duyệt

BAD

GET /shops/123?token=some_kind_of_authenticaiton_token

GOOD
Thay vào đấy, nên truyền vào trong Header

Authorization: Bearer xxxxxx, Extra yyyyy

Ngoài ra, authorization tokens cũng nên có thời gian active ngắn

14. Validate Content-Type

Server không nên giả định content-type. VD, nếu server chấp nhận application/x-www-form-urlencoded, thì hacker có thể tạo một form và trigger một request POST đơn giản.

Vì vậy, cần luôn luôn validate content-type và nếu chỉ cần với các content mặc định, thì có thể validate content-type: application/json

15. Sử dụng HTTP Methods cho các hàm CRUD

HTTP methods phục vụ cho mục đích giải thích các chức năng CRUD

GET: để trả về thông tin của một resource

POST: để tạo một resource mới hoặc các sub resource

PUT: để cập nhật các resource có sẵn, nếu resource không tồn tại thì sẽ tạo mới

PATCH: để cập nhật resource có sắn, nó sẽ chỉ cập nhật các trường được cung cấp và bỏ qua các trường không được gửi

DELETE: xoá các resource đã có

16. Sử dụng Relation cho Nested Resources trong URL

GET /shops/2/products: trả về danh sách products của shop có id 2

GET /shops/2/products/31: trả về thông tin chi tiết của product có id 31 của shop id 2

DELETE /shops/2/products/31: xoá product id 31 và product này thuộc shop id 2

PUT /shops/2/products/31: cập nhật product id 31 và product này thuộc shop . id2

17. CORS

Luôn hỗ trợ CORS (Cross-Origin Resource Sharing) cho tất cả public API

18. Security

Bắt buộc sử dụng HTTPS (TLS-encrypted) cho tất cả endpoints, resources và services, kể cả các callback URL, push notification và webhook

19. Errors

Error được tạo ra khi client tạo một request invalid hay không chính xác, hoặc service thực thi hành động với data và kết quả không đúng. Hoặc gọi đến bên thứ 3 và bên thứ 3 phát sinh lỗi.

VD như chứng thực đăng nhập không đúng, các tham số request không đúng hoặc version không tồn tại, data không tồn tại, …

Với các error code 4xx khi được trả về khi client request không đúng format params, hoặc data không tồn tại.

Để biết rõ hơn, có thể vào trang này

20. Luôn đo đạc thời gian API

Thời gian API tính từ lúc request, xử lý trên server, parse data response và trả về client. Vì test trên local, nên không phải tính network time.

Luôn lưu ý với các API GET, cần ưu tiên trả về data nhanh, còn với API khác (create, update, delete) thì có thể không quan trọng về thời gian thực thi, cần đảm bảo tính toàn vẹn của data

Để đảm bảo API GET đáp ứng được rule về time, cần lưu ý giảm bớt query, sửa lỗi N + 1, tối ưu data trả về, có thể sử dụng query select để lọc trực tiếp các data response ngay trong SQL

Trước khi xây dựng API, cần tạo data non function, lên danh sách các yêu cầu mà API cần thoả mãn, như security, performance, scale, …

21. Luôn đảm bảo tính toàn vẹn data

Không tin tưởng toàn bộ parameter, phải luôn có validate tập dữ liệu cho phép của parameter

Kiểm tra trạng thái dữ liệu trước khi thực hiện cập nhật, VD muốn cập nhật resource lên một trạng thái mới thì phải đảm bảo trạng thái hiện tại là gì

Luôn tính đến kịch bản API được gọi liên tục, đồng thời, khi đấy data sẽ dễ phát sinh các vấn đề dữ liệu bị trùng lặp, cập nhật dữ liệu không chính xác

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ