REST简介

在2000年,罗伊·菲尔德(Roy Fielding)提出了代表性状态转移(REST)作为设计Web服务的体系结构方法。REST是一种用于构建基于超媒体的分布式系统的体系结构样式。REST独立于任何底层协议,不一定与HTTP绑定。但是,大多数常见的REST实现使用HTTP作为应用程序协议,并且本指南重点介绍为HTTP设计REST API。

使用HTTP的RESTful API的一些主要设计原则

URL设计

避免在URI中使用动词,应该采用“动词 + 名词”的设计结构。这是因为HTTP动词应足以描述对资源执行的操作。

比如,GET /articles这个命令,GET是动词,/articles是名词。可以解释为:获取全部文章

使用标准HTTP动词对资源执行操作有:

  • GET:读取(Read)

  • POST:新建(Create)

  • PUT:更新(Update)

  • PATCH:更新(Update),通常是部分更新

  • DELETE:删除(Delete)

    返回格式设计

  • 不要返回纯文本,应该使用JSON作为数据格式,注意这里不是json字符串,而是json对象,所以http header的Content-Type属性要设为application/json

  • 客户端请求时,也要明确告诉服务器,可以接受 JSON 格式,即请求的 HTTP 头的ACCEPT属性也要设成application/json

    使用复数名词

    既然 URL 是名词,那么应该使用复数,还是单数?
    这没有统一的规定。假如现在有两种场景,获取文章id为110的数据。那么我可以这样设计:

  • GET /article/110 可以理解为获取文章,id为110的数据

  • GET /articles/110 可以理解为从数据集中(文章集合)中获取,id为110的数据
    其实这两种都是可以理解的。但是后者更能体现出从数据集中读取数据,跟读取资源的过程更贴切,例如:

    SELECT * FROM articles WHERE id = 110;

    所以为了统一起见,建议都使用复数 URL。

    在响应正文中返回错误详细信息

    当API服务器处理错误时,方便(并建议!)在JSON正文中返回错误详细信息,以帮助用户进行调试。

    {
    "error": "Invalid payoad.",
    "detail": {
      "surname": "This field is required."
    }
    }

    发生错误时,不要返回 200 状态码

    就比如说,HTTP 相应的状态码是200,但是服务器的响应可以是sucess也可能是error:

    HTTP/1.1 200 OK
    Content-Type: text/html
    {
      "status": "failure",
      "data": {
          "error": "Expected at least two items in list."
      }
    }
  • 结果,在判断status状态之前,我必须检查状态码和临时字段,以确保一切正常。这种设计是真正的禁忌,因为它破坏了API及其用户之间的信任。
    所以我们应该怎么做呢?
    使用状态代码,仅使用响应正文提供错误详细信息。

    HTTP/1.1 400 Bad Request
    Content-Type: application/json
    {
       "error": "Expected at least two items in list."
    }

    状态码

    2xx 状态码

    200状态码表示操作成功,但是不同的方法可以返回更精确的状态码。

  • GET: 200 OK

  • POST: 201 Created

  • PUT: 200 OK

  • PATCH: 200 OK

  • DELETE: 204 No Content
    上面代码中,POST返回201状态码,表示生成了新的资源;DELETE返回204状态码,表示资源已经不存在。
    此外,202 Accepted状态码表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。

3xx 状态码

API 用不到301状态码(永久重定向)和302状态码(暂时重定向,307也是这个含义),因为它们可以由应用级别返回,浏览器会直接跳转,API 级别可以不考虑这两种情况。

API 用到的3xx状态码,主要是303 See Other,表示参考另一个 URL。它与302和307的含义一样,也是"暂时重定向",区别在于302和307用于GET请求,而303用于POST、PUT和DELETE请求。收到303以后,浏览器不会自动跳转,而会让用户自己决定下一步怎么办。下面是一个例子。

HTTP/1.1 303 See Other
Location: /articles/110

4xx 状态码

4xx状态码表示客户端错误,主要有下面几种。

  • 400 Bad Request:服务器不理解客户端的请求,未做任何处理。

  • 401 Unauthorized:用户未提供身份验证凭据,或者没有通过身份验证。

  • 403 Forbidden:用户通过了身份验证,但是不具有访问资源所需的权限。

  • 404 Not Found:所请求的资源不存在,或不可用。

  • 405 Method Not Allowed:用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内。

  • 410 Gone:所请求的资源已从这个地址转移,不再可用。

  • 415 Unsupported Media Type:客户端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。

  • 422 Unprocessable Entity :客户端上传的附件无法处理,导致请求失败。

  • 429 Too Many Requests:客户端的请求次数超过限额。

    5xx 状态码

    5xx状态码表示服务端错误。一般来说,API 不会向用户透露服务器的详细信息,所以只要两个状态码就够了。

  • 500 Internal Server Error:客户端请求有效,服务器处理时发生了意外。

  • 503 Service Unavailable:服务器无法处理请求,一般用于网站维护状态。

提供链接

这一种目前比较少用。但是可以考虑用。其实就是在获取资源的时候,直接返回下一步需要操作的URL。例如:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "In progress",
   "links": {[
    { "rel":"cancel", "method": "delete", "href":"/articles/status/110" } ,
    { "rel":"edit", "method": "put", "href":"/articles/status/12345" }
  ]}
}

参考连接

RESTful API Design: 13 Best Practices to Make Your Users Happy, by Florimond Manca
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design