Một số tips để thiết kế APIs hiệu quả
Xây dựng một API phong phú và chuyên nghiệp không phải là khó, nhưng có rất nhiều điều bạn nên xem xét ngay từ đầu. Dưới đây là một số khái niệm quan trọng nhất và thực hành tốt nhất mà tôi học được trong khi xây dựng API với Rails. Sử dụng versioning Ngay cả khi bạn chỉ mới bắt đầu ...
Xây dựng một API phong phú và chuyên nghiệp không phải là khó, nhưng có rất nhiều điều bạn nên xem xét ngay từ đầu. Dưới đây là một số khái niệm quan trọng nhất và thực hành tốt nhất mà tôi học được trong khi xây dựng API với Rails.
Sử dụng versioning
Ngay cả khi bạn chỉ mới bắt đầu phát triển sản phẩm của bạn và không chắc chắn là sau này sẽ có cơ hội để tạo ra những phiên bản tiếp theo của API, thì bạn cũng nên tạo một version cho nó. Sẽ tốn rất ít công sức và cũng dễ dàng hơn rất nhiều để thêm những phiên bản mới khi sản phẩm của bạn đi tới thành công. Nếu bạn có một sản phẩm thành công, bạn hầu như sẽ luôn phải điều chính API của bạn và do đó sẽ cần phải phát hành một phiên bản v2 cho API đó.
Trong Rails, để định nghĩa các phiên bản khác nhau, chúng ta khai báo một namespace đơn giản trong routes như sau:
namespace :api do namespace :v1 do resources :projects end end
Khi đó, đường dẫn đến API trông sẽ dễ đọc như này: api/v1/projects
Tôi khuyến khích bạn nên cài đặt phiên bản của API như là một phần của URL, vì đây là phương pháp rõ ràng, minh bạch nhất đối với người dùng.
Sử dụng HTTP Status Codes đúng
HTTP cung cấp cho bạn một cơ chế tuyệt vời để thông báo cho những người dùng API của bạn nếu như request là thành công hay không: HTTP status codes
Sử dụng các status codes đó đúng sẽ cung cấp cho người dùng những thông tin hữu dụng. Họ sẽ cảm ơn bạn ^ ^. Bảng dưới đây là một số HTTP status codes điển hình của REST-API:
Code | Tên | Ý nghĩa |
---|---|---|
200 | OK | Mọi thứ diễn ra đều tốt. Tôi trả lại tài nguyên bạn đã yêu cầu |
201 | Created | Chúng tôi đã tạo thành công một tài nguyên cho bạn |
204 | No Content | Tôi đã xử lý thành công yêu cầu của bạn và không trả về bất cứ nội dung nào |
401 | Unauthorized | Bạn đã không cung cấp thông tin xác thực hợp lệ |
404 | Not found | Tài nguyên bạn yêu cầu không thể tìm thấy nhưng có thể sẽ có trong tương lai |
422 | Unprocessable Entity | Tài nguyên không thể lưu trữ. Có thể đã xảy ra lỗi xác thực |
Rails controller làm cho API của bạn thực sự thuận tiện để sử dụng đúng các status codes, như sau:
render json: @object, status: :created
Sử dụng đúng HTTP verbs
Bên cạnh những HTTP status codes vô cùng hữu ích, bạn cũng nên sử dụng đúng HTTP verbs. Phổ biến nhất mà bạn cần trong bất kỳ REST-API nào là:
Verb | Cách dùng |
---|---|
GET | Chỉ lấy về dữ liệu. Không bao giờ thay đổi bất kì dữ liệu nào với một GET request |
POST | Tạo mới một tài nguyên |
PUT/PATCH | Cập nhật một tài nguyên đang tồn tại trong hệ thống |
DELETE | Xóa một tài nguyên |
Sử dụng những HTTP verbs đó đúng cách để hướng dẫn người dùng sử dụng đúng API của bạn. Routing method của Rails giúp cho bạn thực hiện đúng các HTTP verbs cho các action của bạn một cách dễ dàng. Xem Rails guide on routing để biết thêm chi tiết.
Trả về error message đúng
Xử lý lỗi trong một API nghe có vẻ dễ dàng nhưng đòi hỏi bạn cần có một kế hoạch cẩn thận. Khuyến khích luôn luôn trả về những error messages trong các định dạng tương tự mà người dùng không cần phải xử lý các ngữ nghĩa khác nhau đối với những tài nguyên khác nhau. Ngoài ra, hãy xem xét một số ngôn ngữ client có thể không hỗ trợ việc nested tùy ý trong JSON response và do đó sẽ gặp một vài rắc rối đối với việc phân tích nó.
Sử dụng HTTP status code ở trên đầu mỗi eror message.
Nếu bạn muốn đi xa hơn nữa, bạn có thể thêm vào một đường dẫn đến bài viết từ document của bạn khi có lỗi xảy ra để người dùng có thể debug vấn đề ngay lập tức. Không có gì tệ hơn là một lỗi không có hoặc thậm chí là có một error message sai. Luôn luôn cố gắng làm những gì có ích đối với người dùng của bạn nhất có thể.
Một error message response tốt có thể trông như sau:
Status: 422 { "message": "Validation Failed", "errors": [ { "resource": "Project", "field": "name", "message": "can't be blank" } ]
Luôn luôn phân trang cho kết quả của bạn
Hãy thử tưởng tượng, một request có tới hàng trăm nghìn cho tới hàng triệu bản ghi được trả về cùng một lúc, điều này dẫn dến sự bất tiện nghiêm trọng đối với database, browser cũng như web-server của bạn. Vì vậy cách tốt nhất để tránh được điều này là bạn nên phân trang cho những kết quả được trả về theo một list.
Phân trang trong Rails có thể dễ dàng được thực hiện bằng cách sử dụng gem như kaminari, nhưng bạn cũng có thể thực hiện nó bằng cách sử dụng LIMIT và OFFSET trong câu truy vấn của bạn.
Khi trả lại kết quả phân trang của bạn, hãy chắc chắn rằng bạn sẽ hiển thị thông tin meta phân trang cho người sử dụng. Tôi đã tìm thấy một cách rất tốt để làm việc này thông qua HTTP Link-Headers trong response.
Header chứa đầy đủ URL đến next, previous, first và last page của kết quả trả về và làm cho nó thực sự dễ dàng để client có thể xử lý kết quả phân trang của bạn.
Link: <https://domain.com/api/v2/projects?page=1>; rel="first", <https://domain.com/api/v2/projects?page=3>; rel="prev", <https://domain.com/api/v2/projects?page=5>; rel="next", <https://domain.com/api/v2/projects?page=9>; rel="last"
Xác thực
Nếu bạn đang xây dựng một private API, điều bạn cần phải làm là xây dựng cơ chế xác thực cho nó. Một số cơ chế xác thực hay được sử dụng như HTTP Basic Authentication và HTTP Digest Authentication : http://guides.rubyonrails.org/action_controller_overview.html#http-authentications. Những cách này khá dễ dàng để thực hiện. Bên cạnh cơ chế xác thực dễ dàng đó, bạn cũng nên cho phép người dùng đăng nhập bằng cách sử dụng một private access tokens. Cách này được khuyên dùng khi bạn xử lý việc truy cập từ private resource của bạn tới một vài external service.
Rate Limiting
Khi người dùng bắt đầu sử dụng API của bạn, bạn có thể không phải lo lắng về hiệu suất hoặc giới hạn tài nguyên của bạn.Tuy nhiên, nếu ứng dụng của bạn thành công và có đến hàng nghìn người dùng bắt đầu tích hợp API vào cơ sở hạ tầng và quy trình làm việc của họ, mọi thứ có thể sẽ đi sai hướng. Vì vậy, để tránh lạm dụng, thì bạn nên xem xét việc thêm rate-limiting vào API của bạn.
Ví dụ, bạn có thể muốn giới hạn việc sử dụng API của mỗi người dùng được nhiều nhất là 100 lần gọi API trong khoảng thời gian là 10 phút. Nếu có quá nhiều request được nhận từ một người dùng trong một khoảng thời gian nhất định, một response với status code là 429 (Có nghĩa là "Có quá nhiều request") nên được trả về.
Khi rate limiting được enabled, mặc định mọi response sẽ được gửi đi kèm với HTTP headers có chứa những thông tin rate limiting hiện tại:
- X-Rate-Limit-Limit, số tối đa request được cho phép với mỗi khoảng thời gian
- X-Rate-Limit-Remaining, số request còn lại trong khoảng thời gian hiện tại
- X-Rate-Limit-Reset, số giây chờ đợi để lấy được tối đa số request cho phép
HTTP Caching: Conditional GET
Với bất kì web service thành công nào, caching trở nên rất quan trọng để đảm bảo cho hiệu suất đạt hiệu quả của hệ thống. HTTP đi cùng với cơ chế caching khá là dễ dàng để sử dụng trong Rails.
Học thêm về HTTP caching trong Rails: Conditional GET
Các phương pháp cần xem xét là self-invalidating cache keys, Russian Doll Caching, và Reverse-Proxy-Caches (Varnish, CDNs).
Document tất tần tật
Công việc document vô cùng nhàm chán, và như bao thứ nhàm chán khác, lại rất cần thiết. Một chương trình với document tốt sẽ cứu rỗi tinh thần của bạn. Bạn sẽ giảm bớt lượng câu hỏi khồng lồ của người dùng về API của bạn, vì dù gì thì “thời gian là vàng bạc” mà.
Document tốt cần có:
- Tổng quan chi tiết và cách làm việc của module
- Javadocs, Heredocs, Rdocs hoặc bất cứ thông tin gì về public method và protocols.
- Code mẫu thể hiện cách sử dụng.
Không phải tất cả cái gì trừu tượng đều yêu cầu cùng một mức document như nhau. Ví dụ như, một class be bé cũng chả cần code mẫu làm gì.
Documentation cần được làm mới liên tục. Nếu bạn nhận được nhiều câu hỏi về cùng hỏi một thứ, bạn có thể thêm vào doc để giải thích cho người dùng mới.
Quá nhiều document cũng sẽ lãng phí thời gian. Và có nhiều phần vô dụng vì chả ai dùng đến cả. Hãy thật sự document những gì hữu ích.
Kết luận
Thiết kế API là cả một nghệ thuật. Hi vọng bài viết trên đây sẽ giúp bạn thiết kế được một API tốt cho bản thân mình. (yeah)
- https://phraseapp.com/blog/posts/best-practice-10-design-tips-for-apis/