RESTful规范Api最佳设计实践

RESTful是目前比较流行的接口路径设计规范,基于HTTP,通常使用JSON方式定义,经过不一样HttpMethod来定义对应接口的资源动做,如:新增(POST)、删除(DELETE)、更新(PUT、PATCH)、查询(GET)等。json

路径设计

RESTful设计规范内,每个接口被认为是一个资源请求,下面咱们针对每一种资源类型来看下API路径设计。api

路径设计注意事项以下所示:app

  • 资源名使用复数
  • 资源名使用名词
  • 路径内不带特殊字符
  • 避免多级URL

新增资源

请求方式 示例路径
POST
https://api.yuqiyu.com/v1/users

新增资源使用POST方式来定义接口,新增资源数据经过RequestBody方式进行传递,以下所示:curl

curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "恒宇少年", 
    "age": 25, 
    "address": "山东济南"
}'复制代码

新增资源后接口应该返回该资源的惟一标识,好比:主键值。url

{
  "id" : 1,
  "name" : "恒宇少年"
}复制代码

经过返回的惟一标识来操做该资源的其余数据接口。spa

删除资源

请求方式 示例路径
备注
DELETE
https://api.yuqiyu.com/v1/users
批量删除资源
DELETE
https://api.yuqiyu.com/v1/users/{id} 删除单个资源

删除资源使用DELETE方式来定义接口。设计

  • 根据主键值删除单个资源
curl -X DELETE https://api.yuqiyu.com/v1/users/1复制代码

将资源的主键值经过路径的方式传递给接口。代理

  • 删除多个资源
curl -X DELETE -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
      "userIds": [
          1, 
          2, 
          3
      ]
  }'复制代码

删除多个资源时经过RequestBody方式进行传递删除条件的数据列表,上面示例中经过资源的主键值集合做为删除条件,固然也能够经过资源的其余元素做为删除的条件,好比:namecode

更新资源

请求方式 示例路径
备注
PUT
https://api.yuqiyu.com/v1/users/{id} 更新单个资源的所有元素
PATCH
https://api.yuqiyu.com/v1/users/{id} 更新单个资源的部分元素

在更新资源数据时使用PUT方式比较多,也是比较常见的,以下所示:orm

curl -X PUT -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users/1 -d '{
    "name": "恒宇少年", 
    "age": 25, 
    "address": "山东济南"
}'复制代码

查询单个资源

请求方式 示例路径
备注
GET
https://api.yuqiyu.com/v1/users/{id}
查询单个资源
GET
https://api.yuqiyu.com/v1/users?name={name} 非惟一标识查询资源

  • 惟一标识查询单个资源
curl https://api.yuqiyu.com/v1/users/1复制代码

经过惟一标识查询资源时,使用路径方式传递标识值,体现出层级关系。

  • 非惟一标识查询单个资源
curl https://api.yuqiyu.com/v1/users?name=恒宇少年复制代码

查询资源数据时不只仅都是经过惟一标识值做为查询条件,也可能会使用资源对象内的某一个元素做为查询条件。

分页查询资源

请求方式 示例路径
GET
https://api.yuqiyu.com/v1/users?page=1&size=20

分页查询资源时,咱们通常须要传递两个参数做为分页的条件,page表明了当前分页的页码,size则表明了每页查询的资源数量。

curl https://api.yuqiyu.com/v1/users?page=1&size=20复制代码

若是分页时须要传递查询条件,能够继续追加请求参数。

https://api.yuqiyu.com/v1/users?page=1&size=20&name=恒宇少年复制代码

动做资源

有时咱们须要有动做性的修改某一个资源的元素内容,好比:重置密码。

请求方式 示例路径
备注
POST
https://api.yuqiyu.com/v1/users/{id}/actions/forget-password -

用户的惟一标识在请求路径中进行传递,而修改后的密码经过RequestBody方式进行传递,以下所示:

curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users/1/actions/forget-password -d '{
    "newPassword": "123456"
}'复制代码

版本号

版本号是用于区分Api接口的新老标准,比较流行的分别是接口路径头信息这两种方式传递。

  • 接口路径方式

咱们在部署接口时约定不一样版本的请求使用HTTP代理转发到对应版本的接口网关,经常使用的请求转发代理好比使用:Nginx等。

这种方式存在一个弊端,若是多个版本同时将请求转发到同一个网关时,会致使具体版本的请求转发失败,咱们访问v1时可能会转发到v2,这并非咱们指望的结果,固然能够在网关添加一层拦截器,经过提取路径上班的版本号来进行控制转发。

# v1版本的请求
  curl https://api.yuqiyu.com/v1/users/1
  # v2版本的请求
  curl https://api.yuqiyu.com/v2/users/1复制代码

  • 头信息方式

咱们能够将访问的接口版本经过HttpHeader的方式进行传递,在网关根据提取到的头信息进行控制转发到对应版本的服务,这种方式资源路径的展示形式不会由于版本的不一样而变化

# v1版本的请求
  curl -H 'Accept-Version:v1' https://api.yuqiyu.com/users/1
  # v2版本的请求
  curl -H 'Access-Version: v2' https://api.yuqiyu.com/users/1复制代码

这两个版本的请求可能请求参数、返回值都不同,可是请求的路径是同样的。

版本头信息的Key能够根据自身状况进行定义,推荐使用Accpet形式,详见Versioning REST Services

状态码

RESTful设计规范内咱们须要充分的里面HttpStatus请求的状态码来判断一个请求发送状态,本次请求是否有效,常见的HttpStatus状态码以下所示:

状态码 发生场景
200
请求成功
201
新资源建立成功
204
没有任何内容返回
400
传递的参数格式不正确
401
没有权限访问
403
资源受保护
404
访问的路径不正确
405
访问方式不正确,GET请求使用POST方式访问
410
地址已经被转移,不可用
415
要求接口返回的格式不正确,好比:客户端须要JSON格式,接口返回的是XML
429
客户端请求次数超过限额
500
访问的接口出现系统异常
503
服务不可用,服务通常处于维护状态。

针对不一样的状态码咱们要作出不一样的反馈,下面咱们先来看一个常见的参数异常错误响应设计方式:

# 发起请求
curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "", 
    "age": 25, 
    "address": "山东济南"
}'
# 响应状态
HttpStatus 200
# 响应内容
{
    "code": "400", 
    "message": "用户名必填."
}复制代码

在服务端咱们能够控制不一样状态码、不一样异常的固定返回格式,不该该将全部的异常请求都返回200,而后对应返回错误,正确的方式:

# 发起请求
curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "", 
    "age": 25, 
    "address": "山东济南"
}'
# 响应状态
HttpStatus 400
# 响应内容
{
    "error": "Bad Request", 
    "message": "用户名必填."
}复制代码

响应格式

接口的响应格式应该统一

每个请求成功的接口返回值外层格式应该统一,在服务端能够采用实体方式进行泛型返回。

以下所示:

/**
 * Api统一响应实体
 * {@link #data } 每一个不一样的接口响应的数据内容
 * {@link #code } 业务异常响应状态码
 * {@link #errorMsg} 业务异常消息内容
 * {@link #timestamp} 接口响应的时间戳
 *
 * @author 恒宇少年 - 于起宇
 */
@Data
public class ApiResponse<T> implements Serializable {
    private T data;
    private String code;
    private String errorMsg;
    private Long timestamp;
}复制代码

  • data

因为每个API的响应数据类型不一致,因此在上面采用的泛型的泛型进行返回,data能够返回任意类型的数据。

  • code

业务逻辑异常码,好比:USERNOTFOUND(用户不存在)这是接口的约定

  • errorMsg

对应code值得描述。

  • timestamp

请求响应的时间戳


总结

RESTfulAPI的设计规范,并非全部的接口都应该遵循这一套规范来设计,不过咱们在设计初期更应该规范性,这样咱们在后期阅读代码时根据路径以及请求方式就能够了解接口的主要完成的工做。

相关文章
相关标签/搜索