什么是RESETful API 设计规范?

现在在开发中前后端都是分离开发,后端提供接口给前台,RESTful 架构,就是目前最流行的一种互联网软件架构,也相当于是接口规范

关于「能愿动词」的使用

为了避免歧义,文档大量使用了「能愿动词」,对应的解释如下:

  • 必须 (MUST):绝对,严格遵循,请照做,无条件遵守
  • 一定不可 (MUST NOT):禁令,严令禁止
  • 应该 (SHOULD) :强烈建议这样做,但是不强求
  • 不该 (SHOULD NOT):强烈不建议这样做,但是不强求
  • 可以 (MAY)可选 (OPTIONAL) :选择性高一点,在这个文档内,此词语使用较少

协议

客户端在通过 API 与后端服务通信的过程中,应该 使用 HTTPS 协议

域名

API 应该部署在专用域名之下,应尽可能保持足够简单。如果确定API 很简单,不会有进一步扩展,可以考虑放在主域名下,这里有两个常见的 URL 根例子:

  • api.example.com/*
  • example.com/api/*

版本(Versioning)

所有的 API 必须保持向后兼容,你 必须 在引入新版本 API 的同时确保旧版本 API 仍然可用。所以 应该 为其提供版本支持

目前比较常见的两种版本号形式:

在 URL 中嵌入版本编号,这种做法是版本号直观、易于调试

api.example.com/v1/*

另一种做法是,将版本号放在 HTTP Header 头中,但不如放入 URL 方便和直观

路径(Endpoints)

路径又称”终点、端点”(endpoint),表示 API 的具体网址

端点就是指向特定资源或资源集合的 URL。在端点的设计中,你 必须 遵守下列约定:

  • URL 的命名 必须 全部小写
  • URL 中资源(resource)的命名 必须 是名词,并且 必须 是复数形式
  • 必须 优先使用 Restful 类型的 URL
  • URL 必须 是易读的
  • URL 一定不可 暴露服务器架构

至于 URL 是否必须使用连字符(-) 或下划线(_),不做硬性规定,但 必须 根据团队情况统一一种风格

来看一个反例

  • https://api.example.com/getUserInfo?userid=1
  • https://api.example.com/getusers
  • https://api.example.com/sv/u
  • https://api.example.com/cgi-bin/users/get_user.php?userid=1

再来看一个正列

  • https://api.example.com/zoos
  • https://api.example.com/animals
  • https://api.example.com/zoos/{zoo}/animals
  • https://api.example.com/animal_types
  • https://api.example.com/employees

HTTP 动词

对于资源的具体操作类型,由 HTTP 动词表示。常用的 HTTP 动词有下面五个(括号里是对应的 SQL 命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

其中

  1. 删除资源 必须DELETE 方法
  2. 创建新的资源 必须 使用 POST 方法
  3. 更新资源 应该 使用 PUT 方法
  4. 获取资源信息 必须 使用 GET 方法

还有两个不常用的 HTTP 动词

  • HEAD:获取资源的元数据
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的

下面是一些例子:

请求方法 URL 描述
GET /zoos 列出所有的动物园(ID 和名称,不要太详细)
POST /zoos 新增一个新的动物园
GET /zoos/{zoo} 获取指定动物园详情
PUT /zoos/{zoo} 更新指定动物园(整个对象)
PATCH /zoos/{zoo} 更新动物园(部分对象)
DELETE /zoos/{zoo} 删除指定动物园
GET /zoos/{zoo}/animals 检索指定动物园下的动物列表(ID 和名称,不要太详细)
GET /animals 列出所有动物(ID 和名称)。
POST /animals 新增新的动物
GET /animals/{animal} 获取指定的动物详情
PUT /animals/{animal} 更新指定的动物(整个对象)
PATCH /animals/{animal} 更新指定的动物(部分对象)
GET /animal_types 获取所有动物类型(ID 和名称,不要太详细)
GET /animal_types/{type} 获取指定的动物类型详情
GET /employees 检索整个雇员列表
GET /employees/{employee} 检索指定特定的员工
GET /zoos/{zoo}/employees 检索在这个动物园工作的雇员的名单(身份证和姓名)
POST /employees 新增指定新员工
POST /zoos/{zoo}/employees 在特定的动物园雇佣一名员工
DELETE /zoos/{zoo}/employees/{employee} 从某个动物园解雇一名员工

过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API 应该 提供参数,过滤返回结果

下面是一些常见的参数:

  • ?limit=10:指定返回记录的数量
  • ?offset=10:指定返回记录的开始位置。
  • ?page=2&per_page=100:指定第几页,以及每页的记录数。
  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
  • ?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许 API 路径和 URL 参数偶尔有重复

比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的

所有 URL 参数 必须 是全小写,必须 使用下划线类型的参数形式

分页参数 必须 固定为 pageper_page

响应(Response)

所有的 API 响应,必须 遵守 HTTP 设计规范,必须 选择合适的 HTTP 状态码。一定不可 所有接口都返回状态码为 200HTTP 响应,如:

HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com

{
    "code": 0,
    "msg": "success",
    "data": {
        "username": "username"
    }
}

或者

HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com

{
    "code": -1,
    "msg": "该 API 不存在",
}

下表列举了常见的 HTTP 状态码

状态码 描述
1xx 代表请求已被接受,需要继续处理
2xx 请求已成功,请求所希望的响应头或数据体将随此响应返回
3xx 重定向
4xx 客户端原因引起的错误
5xx 服务端原因引起的错误

只有来自客户端的请求被正确的处理后才能返回 2xx 的响应,所以当 API 返回 2xx 类型的状态码时,前端 必须 认定该请求已处理成功

必须强调的是,所有 API 一定不可 返回 1xx 类型的状态码。当 API 发生错误时,必须 返回出错时的详细信息。目前常见返回错误信息的方法有两种:

  1. 将错误详细放入 HTTP 响应首部
  2. 直接放入响应实体中

建议参考

1 条评论

发表评论

*