alltools.one
API
2025-06-05
7 min
alltools.one Team
APIRESTJSONResponse FormatBest Practices

API 响应格式:构建一致性 API 的最佳实践

不一致的 API 响应是前端开发者最常抱怨的问题。当每个端点返回的数据结构都不同时,客户端代码中就会充斥着各种特殊处理。一致的响应格式能改善开发者体验、减少 Bug,并使你的 API 具备自文档化能力。

响应信封

将每个响应都包装在一致的结构中:

成功响应(单个资源)

{
  "data": {
    "id": "user_123",
    "name": "Alice",
    "email": "alice@example.com",
    "createdAt": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

成功响应(集合)

{
  "data": [
    { "id": "user_123", "name": "Alice" },
    { "id": "user_456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20,
    "requestId": "req_def456"
  }
}

错误响应

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  },
  "meta": {
    "requestId": "req_ghi789"
  }
}

关键原则:客户端始终检查顶层的 dataerror。永远不要在同一个响应中混合成功数据和错误信息。

使用我们的 JSON 验证器 验证你的响应格式。

HTTP 状态码

正确使用状态码——它们是客户端首先检查的内容:

成功状态码

状态码使用场景
200 OKGET 成功,PUT/PATCH 成功
201 CreatedPOST 创建资源成功
204 No ContentDELETE 成功(无响应体)

客户端错误状态码

状态码使用场景
400 Bad Request请求语法格式错误
401 Unauthorized缺少或无效的身份认证
403 Forbidden已认证但未授权
404 Not Found资源不存在
409 Conflict资源状态冲突(重复)
422 Unprocessable语法正确但语义错误
429 Too Many Requests超出速率限制

服务端错误状态码

状态码使用场景
500 Internal Server Error意外的服务器故障
502 Bad Gateway上游服务故障
503 Service Unavailable临时过载或维护中

错误响应设计

良好的错误响应能帮助开发者快速调试:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 'user_999' not found",
    "details": [],
    "documentationUrl": "https://api.example.com/docs/errors#RESOURCE_NOT_FOUND"
  },
  "meta": {
    "requestId": "req_xyz789",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

规则

  • code 是机器可读的(常量字符串,不是 HTTP 状态码)
  • message 是人类可读的(可以修改而不影响客户端)
  • details 提供验证失败时的字段级错误
  • requestId 使支持团队能在日志中追踪请求

分页模式

基于偏移量的分页

简单且支持跳转到任意页面:

{
  "data": ["..."],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  },
  "links": {
    "first": "/api/users?page=1&per_page=20",
    "prev": "/api/users?page=1&per_page=20",
    "next": "/api/users?page=3&per_page=20",
    "last": "/api/users?page=8&per_page=20"
  }
}

基于游标的分页

更适合实时数据和大型数据集:

{
  "data": ["..."],
  "meta": {
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "next": "/api/users?cursor=eyJpZCI6MTQzfQ&limit=20",
    "prev": "/api/users?cursor=eyJpZCI6MTIzfQ&limit=20&direction=prev"
  }
}

日期和时间

始终使用带时区信息的 ISO 8601 格式:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33+00:00",
  "expiresAt": "2024-12-31T23:59:59Z"
}

不要使用:

  • Unix 时间戳(模糊不清:是秒还是毫秒?)
  • 不带时区的本地日期
  • 自定义格式如 MM/DD/YYYY

关于时间戳处理的更多内容,请参阅我们的 Unix 时间戳指南

Null 与缺失字段

两种常见方法:

包含 null 值(显式):

{ "name": "Alice", "avatar": null, "bio": null }

省略缺失字段(稀疏):

{ "name": "Alice" }

建议:在你的 API 中保持一致。显式 null 值对于强类型语言更好(客户端知道字段存在)。稀疏模式对于带宽受限的环境更好。

响应版本管理

当响应格式发生变化时,请为你的 API 添加版本:

GET /api/v2/users/123

需要版本控制的破坏性变更:

  • 删除字段
  • 更改字段类型
  • 重命名字段
  • 更改响应信封结构

无需版本控制的非破坏性变更:

  • 添加新字段
  • 添加新端点
  • 添加新的枚举值

常见问题

我应该将成功响应包装在 data 键中还是直接返回资源?

使用 data 包装器为所有响应提供了一致的结构,并为元数据、分页和链接留出了空间。直接返回资源对于单资源端点更简单。大多数现代 API 使用包装器方法以保持一致性。

如何处理批量操作中的部分失败?

返回 200 状态码,响应中同时包含成功和失败的结果。使用 207 Multi-Status(WebDAV)是另一种选择,但在 REST API 中不太常用。

相关资源

Published on 2025-06-05
API Response Formats: Best Practices for Consistent APIs | alltools.one