RESTful API 最佳实践

RESTful API 最佳实践

api2

API 的关键要求

  • 网络标准的使用
  • 对开发人员友好,并能通过浏览器地址栏进行探索
  • 简单、直观和一致,使用简单且愉快
  • 足够的灵活性
  • 高效的使用

RESTful API

Media Type

默认媒体类型为 JSON

由于 HTTP 的最新势头和遵循标准,JSON 是最受欢迎的,因此应该明确成为默认的媒体类型

XML 的有点是复杂的场景和历史(SOAP),XML 不是 API 的最佳选择。它冗长,难以解析,难以阅读,其数据模型与大多数编程语言的数据模型不兼容。

HTTP 动词

RESTful 关键原则是将一系列 API 资源通过 域名+资源名称 + HTTP methods

逻辑资源应该从 API 消费者的角度来进行考虑:使用有意义的名词s, 而不是动词,需要明确的是:名词是事物,动词是你对它所做的。

定义资源后,对于每种的资源的不同操作映射为对应的 HTTP 请求方法:

  • GET —— 获取资源信息(SELECT)
  • POST —— 创建新的资源(CREATE)
  • PUT —— 更新资源(UPDATE)
  • PATCH —— 更新部分资源(UPDATE)
  • DELETE —— 删除部分资源(DELETE)
1
2
3
4
5
6
GET /tickets - 检索票证列表
GET /tickets/12 - 检索特定票证
POST /tickets - 创建一个新票
PUT /tickets/12 - 更新票 #12
PATCH /tickets/12 - 部分更新票 #12
DELETE /tickets/12 - 删除票 #12

不适合 CRUD 操作的世界应该怎么办?

  • 组合操作使其看起来像资源的字段。
1
POST /template/apply # 应用一个模版
  • 将其视为符合 RESTful 原则的子资源。
1
GET /zoos/id/animals # 获取某一个 动物园的 动物
  • 无法确定正确的 RESTful 结构的,区别记录即可,无需强制使用。
1
GET /search?text="搜索"

无处不在的 SSL

SSL 证书是一个数字证书,用于认证网站的身份并启用加密连接。SSL 代表安全套接字层,这是一个安全协议,可在 Web 服务器和 Web 浏览器之间创建加密链接。

始终使用 SSL —— 出于安全考虑。

始终使用 SSL 的另外一个优势是有保证的加密通信简化了身份验证工作——您可以使用简单的访问令牌,而不必签署每个 API 请求。

API 接口文档

API 的好坏取决于它的文档。这些文档应该很容易找到并且可以公开访问。大多数开发人员在尝试任何集成工作之前都会查看文档。

文档应显示完整请求/响应周期的示例。

一旦你发布了一个公共 API,就应该发布通知信息,告知关注者变更消息。

例如 Apifox、yapi 等接口文档软件

版本控制

始终对您的 API 进行版本控制。版本控制可帮助您更快地迭代并防止无效请求到达更新的端点。它还有助于平滑任何主要的 API 版本转换。

关于 API 版本应包含在 URL 中还是 header 中?有广泛的争论。

本人比较喜欢将版本控制置于 URL 中

1
GET /api/v1/zoos

结果过滤、排序和搜索

最好使基本资源 URL 尽可能精简。

复杂的结果过滤器、排序要求和高级搜索(当仅限于单一类型的资源时)都可以作为基本 URL

之上的查询参数轻松实现。

例如:

1
2
GET /tickets?state=open
GET /tickets?order_by=create_time:desc,apply_time:desc

JSON 采用 request body 输入

  • POST
  • PUT
  • PATCH

上述方法采用 request body 传输数据

字段名称的 snake_case 与 camelCase

根据 2010 年对 camelCase 和 snake_case (PDF)的眼动追踪研究,**snake_case 比 camelCase 更容易阅读 20%**这种对可读性的影响会影响 API 的可探索性和文档中的示例。

分页

json 返回数据中,会包含一些分页数据;

The right way to include pagination details today is using the Link header introduced by RFC 8288.

以下是正确使用 Link 标头的示例,来自 GitHub:

1
Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next", <https://api.github.com/user/repos?page=50&per_page=100>; rel="last"

许多 API 确实需要额外的分页信息,例如可用结果总数的计数。需要发送计数的 API 可以使用自定义 HTTP 标头,如 X-Total-Count

更新和限制资源应该返回资源表示

PUT、POST 或 PATCH 调用可能会修改不属于所提供参数的基础资源字段(例如:created_at 或 updated_at 时间戳)。为防止 API 使用者必须再次点击 API 以获得更新的表示,让 API 返回更新(或创建)的表示作为响应的一部分。

如果 POST 导致创建,请使用 HTTP 201 状态码并包含指向新资源 URL 的 Location 标头。

除了将新创建的资源表示作为响应主体之外,还应该包含这两个内容。

默认情况下,不使用 envelope, 特殊情况下使用

许多情况下:

1
2
3
4
5
6
{
"data":{
"id": 123,
"name": "John"
}
}

理由:

  • 包含额外的元数据或分页信息,一些 REST 客户端不允许轻松访问 HTTP 标头,而 JSONP 请求无法访问 HTTP 标头。然而,随着 CORS 和 RFC 5988 等 Link 标头等标准被迅速采用,封装开始变得不必要了。

速率限制

为防止滥用,标准做法是向 API 添加某种速率限制。

To prevent abuse, it is standard practice to add some sort of rate limiting to an API. RFC 6585 introduced a HTTP status code 429 Too Many Requests to accommodate this.

However, it can be very useful to notify the consumer of their limits before they actually hit it. This is an area that currently lacks standards but has a number of popular conventions using HTTP response headers.

At a minimum, include the following headers:

  • X-Rate-Limit-Limit - The number of allowed requests in the current period
  • X-Rate-Limit-Remaining - The number of remaining requests in the current period
  • X-Rate-Limit-Reset - The number of seconds left in the current period

Authentication

RESTful API 应该是无状态的。

基于 SSL 身份验证凭据可以简化为随机生成的访问令牌,该令牌在 HTTP 基本身份验证的用户名字段中传送。

  • session
  • jwt
  • access_token
  • OAuth 2

Cache

HTTP 内置缓存框架

  • ETag
  • Last-Modified

Error Handler

类似 HTML 错误页面向访问者显示有用的错误信息一样,API 应该以已知的可使用格式提供有用的错误信息。错误的表示应该与任何资源的表示没有区别,只是具有自己的一组字段。

  • API 应返回合理的 HTTP 状态代码。

API 错误通常分为两种类型:

  • 客户端问题的 400 系列状态代码
  • 服务器问题的 500 系列状态代码

对于具体的 400 系列和 500 系列状态代码,应带有可使用的 JSON 错误表示。

JSON 错误正文应具有:

  • 错误信息
  • 唯一的错误代码
  • 以及可能的详细描述
1
2
3
4
5
{
"code" : 1234,
"message" : "Something bad happened :(",
"description" : "More details about the error here"
}

HTTP status codes

  • 200 OK - Response to a successful GET, PUT, PATCH or DELETE. Can also be used for a POST that doesn’t result in a creation.
  • 201 Created - Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource
  • 204 No Content - Response to a successful request that won’t be returning a body (like a DELETE request)
  • 304 Not Modified - Used when HTTP caching headers are in play
  • 400 Bad Request - The request is malformed, such as if the body does not parse
  • 401 Unauthorized - When no or invalid authentication details are provided. Also useful to trigger an auth popup if the API is used from a browser
  • 403 Forbidden - When authentication succeeded but authenticated user doesn’t have access to the resource
  • 404 Not Found - When a non-existent resource is requested
  • 405 Method Not Allowed - When an HTTP method is being requested that isn’t allowed for the authenticated user
  • 410 Gone - Indicates that the resource at this end point is no longer available. Useful as a blanket response for old API versions
  • 415 Unsupported Media Type - If incorrect content type was provided as part of the request
  • 422 Unprocessable Entity - Used for validation errors
  • 429 Too Many Requests - When a request is rejected due to rate limiting
  • 200 OK - 对成功的 GET、PUT、PATCH 或 DELETE 的响应。也可用于不会导致创建的 POST。
  • 201 已创建- 对导致创建的 POST 的响应。应与指向新资源位置的Location 标头结合
  • 204 No Content - 对不会返回正文的成功请求的响应(如 DELETE 请求)
  • 304 Not Modified - 在使用 HTTP 缓存标头时使用
  • 400 Bad Request - 请求格式错误,比如请求体没有解析
  • 401 Unauthorized - 当没有提供或提供无效的身份验证详细信息时。如果从浏览器使用 API,也可用于触发身份验证弹出窗口
  • 403 Forbidden - 当身份验证成功但经过身份验证的用户无权访问资源时
  • 404 Not Found - 当请求不存在的资源时
  • 405 Method Not Allowed - 当请求的 HTTP 方法不允许经过身份验证的用户使用时
  • 410 Gone - 表示此端点的资源不再可用。作为对旧 API 版本的全面响应很有用
  • 415 Unsupported Media Type - 如果作为请求的一部分提供了不正确的内容类型
  • 422 Unprocessable Entity - 用于验证错误
  • 429 Too Many Requests - 当请求由于速率限制而被拒绝时

In Summary

API 是开发人员的用户界面。努力确保它不仅功能齐全而且使用起来愉快。

由于开发语言有异,只有最适合的 API 规范,没有最好的 API 规范

参考

Best Practices for Designing a Pragmatic RESTful API:https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

Idel restful api : https://betimdrenica.wordpress.com/2015/03/09/ideal-rest-api-design/

https://www.ruanyifeng.com/blog/2014/05/restful_api.html

-------------THANKS FOR READING-------------