Better API¶
some rule/advice to design better apis.
-
一致性
- 同样的命名规则(I prefer snake_case)
- uri命名用统一的单数或复数格式(I like plural)
- 使用一致的
auth
方案。 - 使用一致的
headers
- 使用统一的statuscode,比如
404
表示未找到。 - 对于同类操作,使用同样的
http-method
-
ISO8601 UTC时间表示法
{ "published_at": "2022-03-03T21:59:08Z" }
-
对于public/private endpoints 进行管理
- 对于public endpoints 按需要抛出
auth exception
- 对于public endpoints 按需要抛出
-
提供 health check endpoint
- for example:
/health
or/ping
- for example:
-
尽早进行API version管理
- version the api,或者从url,或者parameter, 或者 header
https://api.life.com/v1/health https://api.life.com/health?api_version=1.0
-
承认 API 的 key auth
- 自定义
Api-Key
放于header中,同时制定过期机制,以及避免将key
这种敏感信息放置到源代码中(建议用 environment variables 控制)
- 自定义
-
使用通用的HTTP status code
200 for general success 201 for successful creation 400 for bad requests from the client 401 for unauthorized requests 403 for missing permissions 404 for missing resources 429 for too many requests 5xx for internal errors (these should be avoided at all costs)
-
使用通用的 HTTP method
POST for creating GET for reading PATCH for partial updates PUT for full updates DELETE for deleting # example: POST /users GET /users GET /users/{id} PATCH /users/{id} PUT /users/{id} DELETE /users/{id}
-
用高效词汇作为URL
- url面向资源,避免用无关信息等。
# GOOD: GET /users => Retrieve users DELETE /users/{id} => Delete a user POST /users/{id}/notifications => Create a notification for a specific user user.first_name order.number # BAD: GET /getUser POST /updateUser POST /notification/user order.ordernumber user.firstName
-
使用标准的error responses
// Request => GET /users/4TL011ax // Response <= 404 Not Found { "code": "user/not_found", "message": "A user with the ID 4TL011ax could not be found." }
-
POST返回创建后的资源
// Request: POST /users { "email": "jdoe@averagecompany.com", "name": "John Doe" } // Response { "id": "T9hoBuuTL4", "email": "jdoe@averagecompany.com", "name": "John Doe" }
-
PATCH 优于 PUT
- 因为整体替换太危险了
-
命名尽量specifig
- 避免给人歧义或者误导用户
-
使用分页
- 尽早规划分页,不论是
simple pagination
还是deep pagination
// Request => GET /users?page_number=1&page_size=15 // Response <= 200 OK { "page_number": 1, "page_size": 15, "count": 378, "data": [ // resources ], "total_pages": 26, "has_previous_page": true, "has_next_page": true }
- 尽早规划分页,不论是
-
允许扩展资源
- 在很多时候尽量允许使用
expand
, 一方面避免round-trips
, 一方面避免加载所有数据
// Request => GET /users/T9hoBuuTL4?expand=orders&expand=orders.items // Response <= 200 OK { "id": "T9hoBuuTL4", "email": "jdoe@averagecompany.com", "name": "John Doe", "orders": [ { "id": "Hy3SSXU1PF", "items": [ { "name": "API course" }, { "name": "iPhone 13" } ] }, { "id": "bx1zKmJLI6", "items": [ { "name": "SaaS subscription" } ] } ] }
- 在很多时候尽量允许使用