Web API Standards
Tổng quan API (Application Programing Interface) là một giao tiếp phần mềm được dùng bởi các ứng dụng khác nhau. RESTful API là một chuẩn API phổ biến hiện nay. Vậy làm sao có thể viết được một API theo chuẩn RESTful? Sau đây là một số gợi ý. Để bài viết dễ hiểu mình sẽ dùng một số thuật ngữ bằng ...
Tổng quan
API (Application Programing Interface) là một giao tiếp phần mềm được dùng bởi các ứng dụng khác nhau. RESTful API là một chuẩn API phổ biến hiện nay. Vậy làm sao có thể viết được một API theo chuẩn RESTful? Sau đây là một số gợi ý. Để bài viết dễ hiểu mình sẽ dùng một số thuật ngữ bằng tiếng Anh.
RESTful URLs
Hướng dẫn chung cho RESTful URLs
- Một URL định danh một tài nguyên hệ thống (resource)
- URL nên bao gồm danh từ, không dùng động từ.
- Sử dụng danh từ số nhiều cho thống nhất, không dùng danh từ số ít.
- Sử dụng HTTP verbs (GET, POST, PUT, DELETE) để thực thi trên các collections và elements.
- Không cần tạo url sâu hơn resource/identifier/resource.
- Để phiên bản (version number) tại base URL. Ví dụ: http://example.com/v1/path/to/resource.
- URL v. header:
- Nếu nó thay đổi logic bạn viết để tổ chức trả về (response), đặt nó trong URL.
- Nếu nó không thay đổi logic cho mỗi response như thông tin Oauth, đặt nó trên header.
- Chỉ định các trường tùy chọn (optional fields) trong danh sách ngăn cách bởi dấu phẩy. Ví dụ: http://www.example.gov/api/v1/magazines.json ?fields=username,age
- Formats nên có dạng api/v2/resource/{id}.json
Các ví dụ về good URL
- Danh sách magazine:
- GET http://www.example.gov/api/v1/magazines.json
- Filter như một query:
- GET http://www.example.gov/api/v1/magazines.json?year=2011&sort=desc
- GET http://www.example.gov/api/v1/magazines.json?topic=economy&year=2011
- Một magazine dạng JSON format:
- GET http://www.example.gov/api/v1/magazines/1234.json
- Tất cả các articles thuộc magazine này:
- GET http://www.example.gov/api/v1/magazines/1234/articles.json
- Tất cả articles của magazine này dạng XML format:
- GET http://example.gov/api/v1/magazines/1234/articles.xml
- Chỉ định danh sách optional fields ngăn cách bởi dấu phẩy:
- GET http://www.example.gov/api/v1/magazines/1234.json?fields=title,subtitle,date
- Thêm một article cho một magazine cụ thể:
- POST http://example.gov/api/v1/magazines/1234/articles
Ví dụ về bad URL
- Dùng danh từ số ít:
- http://www.example.gov/magazine
- http://www.example.gov/magazine/1234
- http://www.example.gov/publisher/magazine/1234
- Sử dụng động từ trong URL:
- http://www.example.gov/magazine/1234/create
- Filter bên ngoài query string
- http://www.example.gov/magazines/2011/desc
HTTP Verbs
HTTP verbs hoặc methods nên sử dụng dưới chuẩn HTTP/1.1. Dưới đây là ví dụ map HTTP verbs với các hành động tạo, đọc, chỉnh sửa, xóa:
HTTP METHOD | POST | GET | PUT | DELETE |
---|---|---|---|---|
CRUD OP | CREATE | READ | UPDATE | DELETE |
/dogs | Create new dogs | List dogs | Bulk update | Delete all dogs |
/dogs/1234 | Error | Show Bo | If exists, update Bo; If not, error | Delete Bo |
(Example from Web API Design, by Brian Mulloy, Apigee.)
Responses
- Không để giá trị (values) trong khóa (keys)
- Thông tin mở rộng (metadata) nên chỉ chứa những thuộc tính của các gói dữ liệu trả về, chứ không phải thuộc tính của những thành phần có trong gói dữ liệu đó. Ví dụ không trả về thông tin của type của magazine trong tập results.
{ "metadata": { "resultset": { "count": 123, "offset": 0, "limit": 10 } }, "results": [ { "id": "1234", "type": "magazine", "title": "Public Water Systems", "tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], "created": "1231621302" }, { "id": 2351, "type": "magazine", "title": "Public Schools", "tags": [ {"id": "125", "name": "Elementary"}, {"id": "834", "name": "Charter Schools"} ], "created": "126251302" } ] }
Good
Không để giá trị nằm trong khóa:
"tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ],
Bad
Giá trị nằm trong khóa:
"tags": [ {"125": "Environment"}, {"834": "Water Quality"} ],
Tổ chức lỗi (Error handling)
Các phản hồi lỗi nên bao gồm một HTTP status code chung, tin nhắn cho developer, tin nhắn cho người dùng cuối (khi phù hợp) và mã lỗi trong (internal error code) , đường dẫn tới nơi developer có thể tìm thêm thông tin. Ví dụ:
{ "status" : 400, "developerMessage" : "Verbose, plain language description of the problem. Provide developers suggestions about how to solve their problems here", "userMessage" : "This is a message that can be passed along to end-users, if needed.", "errorCode" : "444444", "moreInfo" : "http://www.example.gov/developer/path/to/help/for/444444, http://drupal.org/node/444444", }
Sử dụng 3 mã lỗi phản hồi đơn giản sau: (1) thành công, (2) thất bại vì có vấn đề với client-side, (3) thất bại vì có vấn đề với server-side :
- 200 - OK
- 400 - Bad Request
- 500 - Internal Server Error
Phiên bản (Versions)
- Không bao giờ release một api mà không có một số phiên bản (version number).
- Phiên bản nên là số tự nhiên, không dùng số thập phân, với prefix là v. Ví dụ:
- Good: v1, v2, v3
- Bad: v-1.1, v1.2, 1.3
- Bảo trì APIs ít nhất một phiên bản trở lại (phiên bản trước đó).
Giới hạn số lượng bản ghi (limit) trả về
- Nếu không chỉ định giới hạn thì kết quả trả về với một giá trị giới hạn mặc định (limit = 20, 50)
- Để lấy bản ghi từ 51 – 75 thì làm như sau:
- http://example.gov/magazines?limit=25&offset=50
- offset=50 nghĩa là, ‘bỏ qua 50 bản ghi đầu tiên’ :
- limit=25 nghĩa là, ‘trả về tối đa 25 bản ghi’
Thông tin về giới hạn bản ghi (limit) và tổng số bản ghi (total) cũng nên trả về trong response. Ví dụ:
{ "metadata": { "resultset": { "count": 227, "offset": 25, "limit": 25 } }, "results": [] }
Ví dụ về Request và Response
API Resources
- GET /magazines
- GET /magazines/[id]
- POST /magazines/[id]/articles
GET /magazines
Ví dụ: http://example.gov/api/v1/magazines.json
Response body:
{ "metadata": { "resultset": { "count": 123, "offset": 0, "limit": 10 } }, "results": [ { "id": "1234", "type": "magazine", "title": "Public Water Systems", "tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], "created": "1231621302" }, { "id": 2351, "type": "magazine", "title": "Public Schools", "tags": [ {"id": "125", "name": "Elementary"}, {"id": "834", "name": "Charter Schools"} ], "created": "126251302" } { "id": 2351, "type": "magazine", "title": "Public Schools", "tags": [ {"id": "125", "name": "Pre-school"}, ], "created": "126251302" } ] }
GET /magazines/[id]
Ví dụ: http://example.gov/api/v1/magazines/[id].json
Response body:
{ "id": "1234", "type": "magazine", "title": "Public Water Systems", "tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], "created": "1231621302" }
POST /magazines/[id]/articles
Ví dụ: Tạo mới – POST http://example.gov/api/v1/magazines/[id]/articles
Request body:
[ { "title": "Raising Revenue", "author_first_name": "Jane", "author_last_name": "Smith", "author_email": "jane.smith@example.gov", "year": "2012", "month": "August", "day": "18", "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ante ut augue scelerisque ornare. Aliquam tempus rhoncus quam vel luctus. Sed scelerisque fermentum fringilla. Suspendisse tincidunt nisl a metus feugiat vitae vestibulum enim vulputate. Quisque vehicula dictum elit, vitae cursus libero auctor sed. Vestibulum fermentum elementum nunc. Proin aliquam erat in turpis vehicula sit amet tristique lorem blandit. Nam augue est, bibendum et ultrices non, interdum in est. Quisque gravida orci lobortis... " } ]
Giả lập trả về (Mock Responses)
Nên gợi ý mỗi resource chấp nhận một tham số 'giả lập' trên server test. Khi có tham số này thì nên trả về một dữ liệu giả lập ( dữ liệu mẫu).
Thực thi tính năng này sớm ở môi trường phát triển (development) đảm bảo rằng API sẽ được mô phỏng response như trên production và hỗ trợ cho việc test.
Chú ý: nếu tham số giả lập được truyền trong request trên môi trường production thì phải trả về lỗi.
Tham khảo
- White House Web API standards
- Designing HTTP Interfaces and RESTful Web Services
- API Facade Pattern, by Brian Mulloy, Apigee
- Web API Design, by Brian Mulloy, Apigee
- Fielding's Dissertation on REST