嘘~ 正在从服务器偷取页面 . . .

RESTful 接口设计规范


RESTful 接口设计规范

相关链接:

一、概述

本文学习 RESTful API 设计相关的一些原则和规范。

少量的API在使用时不知不觉,但是当后续API不断增加了,需求变动也会导致API版本的变化。主要是为了可以进行规范化开发,并非是只能使用该规范,其他做法亦可,只是作为前人大佬已经在实践中进行总结整理。学习好的编程设计规范总是便捷有利的。

二、常见规范

1、协议和域名

API通讯使用http协议,如果能使用https尽量使用https。

尽量使用独立域名,

https://api.zhangxiaocai.cn

http://api.zhangxiaocai.cn

如果不能使用可以以api 打头区分访问

https://zhangxiaocai.cn/api

2、版本变化

常见的三种版本方式:

  1. 在uri中放版本信息:GET /v1/users/1
  2. Accept Header:Accept: application/json+v1
  3. 自定义 Header:X-Api-Version: 1

推荐用第一种,虽然没有那么优雅,最明显最方便。

3、URI资源

(1)URI概念

URI 表示资源,资源一般对应服务器端领域模型中的实体类。
URI规范

  • 不用大写;
  • 用中杠-而不用下杠_;
  • 参数列表要encode;
  • URI中的名词表示资源集合,使用复数形式;
  • 避免层级过深
  • 带上版本号

(2)资源路径

资源集合:

所有动物园

/zoos/    

id为1的动物园内的所有动物

/zoos/1/animals

单个资源:

比如:id为1的动物园

/zoos/1      

id为1,2,3的动物园

/zoos/1;2;3   

层级过深资源:

过深的导航容易导致url膨胀,不易维护,如 GET /zoos/1/areas/3/animals/4,尽量使用查询参数代替路径中的实体导航,如GET /animals?zoo=1&area=3;

4、操作类型

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个。

HTTP动作含义对应的SQL操作
GET从服务器取出资源(一项或多项)SELECT
POST在服务器新建一个资源。CREATE
PUT在服务器更新资源(客户端提供改变后的完整资源)UPDATE
PATCH在服务器更新资源(客户端提供改变的属性)UPDATE
DELETE从服务器删除资源。DELETE
HEAD获取资源的元数据。
OPTIONS获取信息,关于资源的哪些属性是客户端可以改变的。

示例:

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

5、条件过滤

记录数量很多,不能全返回,需要对数据进行过滤。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 的含义是相同的。

6、状态码

(1)常规状态码

常规的状态主要是参考 HTTP 状态码。

  • 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
  • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
  • 204 NO CONTENT - [DELETE]:用户删除数据成功。
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
  • 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
  • 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
  • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
  • 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
  • 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
  • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

HTTP状态码

(2)业务类状态码

系统较多的时候,将系统码也带上,使用数字的定义也可以参考HTTP进行设计。

业务系统码+四位数字

具体的可以根据需求来。

(3)错误与异常

发生错误或异常时:

  1. 不响应2xx开头的状态码,客户端可能会缓存成功的http请求;

  2. 正确设置http状态码,遵循HTTP协议规范;

  3. Response body 需要提供的信息

    ​ 1) 错误的代码,方便定位日志,排查问题;

    ​ 2) 直接正面的描述错误的文本。

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

状态码场景
400参数校验失败
401未验证的用户,未登录
403无权限
404资源不存在
500非业务类异常

业务类异常,一般自定义Exception,见词知义。

常规异常:

{
    "status":"failed",
    "code":400"error": "参数xxx校验失败"
}

业务类异常:系统名为ABCD

{
    "status":"failed",
    "code":ABCD2001,
    "error": "XXX数据已经过期。"

}

(4)正常返回

正常返回,减少数据层级。

判断操作成功失败的标记 和操作的单个数据

{
    "success": true,
    "code": 200"info": "操作成功""data": {"id":"1","name":"zhangxiaocai"}
}

info 可选。

分页查询

{
    "paging":{"limit":10,"offset":0,"total":119},
    "data":[{},{},{}...]
}

操作与响应

HTTP操作响应格式
GET状态标记+集合、单个对象
POST状态标记+新增成功的对象
PUT/PATCH状态标记+更新成功的对象
DELETE状态标记

(5)异步任务

对耗时的异步任务,服务器端接受客户端传递的参数后,应返回创建成功的任务资源,其中包含了任务的执行状态。客户端可以轮训该任务获得最新的执行进度。

比如常见信息:

任务ID,任务执行状态,发起人。
请求:

GET /task/3    

返回:

{"taskId":3,"createBy":"Anonymous","status":"success"}

{"taskId":3,"createBy":"Anonymous","status":"running"}

批量请求:

POST /batchTasks/1;2;3;

批量返回:

[{"taskId":3,"createBy":"Anonymous","status":"success"},{},{}...]

[{"from":0,"to":1,"info":"Runing 50 %"},{},{}...]

如果任务的执行状态包括较多信息,可以把“执行状态”抽象成组合资源,客户端查询该状态资源了解任务的执行情况。

提交:

GET /task/3/status

返回:

{"progress":"50%","total":18,"success":8,"fail":1}

7、Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

比如,当用户向api.doname.com的根目录发出请求,会得到这样一个文档。

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。

Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

8、数据格式

JSON 或 XML 按要求使用即可。



版权声明: 本博客所有文章除特別声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明来源 Small-Rose / 张小菜 !
评论
  目录