在 REST API 中使用 JSON:最佳实践
REST API 中的 JSON
JSON 和 REST API 是天作之合。JSON 轻量级的语法、原生的数组支持以及普遍的语言支持,使其成为现代 Web API 的默认格式。但仅仅在 API 中使用 JSON 是不够的 -- 遵循既定的约定和最佳实践,才能确保你的 API 一致、直观且易于集成。
请求和响应格式
一致的封装结构
为所有 API 响应采用一致的 JSON 封装。这使客户端处理具有可预测性,并简化错误处理。
{
"status": "success",
"data": {
"user": {
"id": 123,
"name": "Alice",
"email": "alice@example.com"
}
},
"meta": {
"requestId": "req-a1b2c3d4",
"timestamp": "2026-07-19T10:30:00Z"
}
}
Snake Case 与 Camel Case
选择一种命名约定,并在整个 API 中始终坚持使用:
- Camel Case(
createdAt、firstName):常见于 JavaScript/TypeScript 生态系统 - Snake Case(
created_at、first_name):常见于 Python、Ruby 和 PHP 生态系统
无论你选择哪种,都要清楚地记录下来;如果你的后端语言使用不同的约定,可以考虑使用一层转换层。
HTTP 状态码与 JSON
恰当的 HTTP 状态码能补充你的 JSON 响应。请一致地使用它们:
| 状态码 | 含义 | 使用场景 |
|-------------|---------|-------------|
| 200 OK | 成功 | GET、PUT、PATCH 成功 |
| 201 Created | 资源已创建 | POST 成功 |
| 204 No Content | 删除成功 | DELETE 成功(无 JSON 响应体) |
| 400 Bad Request | JSON 语法无效 | 请求体格式错误 |
| 401 Unauthorized | 需要身份验证 | 令牌缺失或无效 |
| 403 Forbidden | 权限不足 | 身份验证有效但不被允许 |
| 404 Not Found | 资源不存在 | ID 或路径无效 |
| 422 Unprocessable Entity | 校验失败 | 有效 JSON 中的语义错误 |
| 429 Too Many Requests | 触发速率限制 | 客户端超出限制 |
| 500 Internal Server Error | 服务器端故障 | 意外错误 |
标准错误响应格式
{
"status": "error",
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body contains invalid fields",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "INVALID_FORMAT"
},
{
"field": "age",
"message": "Must be a positive integer",
"code": "OUT_OF_RANGE"
}
]
}
}
嵌套资源
表示关系
REST API 经常需要表示相关资源。以下是常见模式:
嵌入式(eager loading):
{
"order": {
"id": 5001,
"total": 29.99,
"customer": {
"id": 123,
"name": "Alice",
"email": "alice@example.com"
},
"items": [
{
"productId": 42,
"name": "Widget",
"quantity": 2,
"price": 14.99
}
]
}
}
引用式(lazy loading)-- 使用 ID 并提供单独的端点:
{
"order": {
"id": 5001,
"total": 29.99,
"customerId": 123,
"itemIds": [101, 102]
}
}
经验法则: 嵌入总是需要一起获取的相关数据。对按条件或在不同时间获取的数据使用引用。
分页模式
在返回资源列表时,分页必不可少。请使用一致的分页格式:
基于偏移量的分页
{
"status": "success",
"data": [
{ "id": 1, "name": "User 1" },
{ "id": 2, "name": "User 2" }
],
"pagination": {
"page": 1,
"perPage": 20,
"totalItems": 156,
"totalPages": 8,
"links": {
"first": "/api/users?page=1&perPage=20",
"prev": null,
"next": "/api/users?page=2&perPage=20",
"last": "/api/users?page=8&perPage=20"
}
}
}
基于游标的分页(推荐用于大数据集)
{
"status": "success",
"data": [
{ "id": 100, "name": "User 100" },
{ "id": 101, "name": "User 101" }
],
"pagination": {
"nextCursor": "eyJpZCI6MTAxfQ==",
"hasMore": true
}
}
对于新记录可能改变页面边界的实时数据,基于游标的分页更可靠。
API 请求中的 JSON
POST / PUT 请求体
使用 Content-Type: application/json 请求头接受 JSON:
{
"title": "New Blog Post",
"content": "This is the content...",
"tags": ["json", "rest-api"],
"published": false
}
使用 PATCH 进行部分更新
使用 PATCH 进行部分更新。只接受应该变更的字段:
// PATCH /api/users/123
{
"email": "newemail@example.com"
}
过滤、排序和搜索
使用查询参数进行数据操作,保持 JSON 请求体干净整洁:
GET /api/users?filter[role]=admin&sort=-createdAt&search=alice
{
"status": "success",
"data": [ /* filtered, sorted results */ ]
}
速率限制
在响应头中包含速率限制信息,也可以选择性地包含在 JSON 响应体中:
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again later."
},
"meta": {
"rateLimit": {
"limit": 100,
"remaining": 0,
"resetAt": "2026-07-19T11:00:00Z"
}
}
}
JSON 最佳实践清单
- [ ] 使用一致的键命名(全程使用 camelCase 或 snake_case)
- [ ] 每次响应都返回恰当的 HTTP 状态码
- [ ] 包含一致的错误格式,并带有机器可读的错误码
- [ ] 使用标准化的分页对象对列表端点进行分页
- [ ] 使用 JSON Schema 记录并校验请求/响应结构
- [ ] 在所有 JSON 端点设置
Content-Type: application/json - [ ] 在生产环境中使用 gzip 或 brotli 压缩 JSON 响应
- [ ] 强制执行最大负载大小限制(例如默认为 1MB)
- [ ] 使用 HTTPS 加密传输中的 JSON 数据
- [ ] 结构化错误详情,帮助客户端调试而不暴露内部信息
校验你的 API JSON
在 API 响应到达客户端之前,先用 JSON 校验器校验一遍,以便尽早发现格式化错误。一致且有效的 JSON 响应能让你的 API 可靠且对开发者友好。在开发过程中,可以使用我们的 JSON Formatter & Validator 工具来测试你的数据负载。