专栏首页SpringBoot 核心技术RESTful规范Api最佳设计实践

RESTful规范Api最佳设计实践

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

路径设计

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

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

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

新增资源

请求方式

示例路径

POST

https://api.yuqiyu.com/v1/users

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

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

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

{
  "id" : 1,
  "name" : "恒宇少年"
}

通过返回的唯一标识来操作该资源的其他数据接口。

删除资源

请求方式

示例路径

备注

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方式进行传递删除条件的数据列表,上面示例中通过资源的主键值集合作为删除条件,当然也可以通过资源的其他元素作为删除的条件,比如:name

更新资源

请求方式

示例路径

备注

PUT

https://api.yuqiyu.com/v1/users/{id}

更新单个资源的全部元素

PATCH

https://api.yuqiyu.com/v1/users/{id}

更新单个资源的部分元素

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

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形式,详见<a href="http://www.informit.com/articles/article.aspx?p=1566460" target="_blank">Versioning REST Services</a>。

状态码

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 业务逻辑异常码,比如:USER_NOT_FOUND(用户不存在)这是接口的约定
  • errorMsg 对应code值得描述。
  • timestamp 请求响应的时间戳

总结

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html

    徐飞机
  • 90行代码,15个元素实现无限滚动

    无限下拉加载技术使用户在大量成块的内容面前一直滚动查看。这种方法是在你向下滚动的时候不断加载新内容。

    前端劝退师
  • 干货 | Node.js 在转转的微服务实践(一)

    微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好...

    五月君
  • 使用CURL命令操作ES

    趣学程序
  • 预防XSS,这几招管用!

    大家应该都听过 XSS (Cross-site scripting) 攻击问题,或多或少会有一些了解,但貌似很少有人将这个问题放在心上。一部分人是存有侥幸心理:...

    黄泽杰
  • GraphQL 优势之处

    举个例子,Book对象有bookTypeId,那我想看对应的bookTypeName,bookType对应的summary咋办? 如果你用RESTful Ap...

    从今若
  • 【大咖连载】服务设计与实现

    服务设计会影响到业务需求是否被正确、高效地实现,良好的服务设计能够帮助领域专家与开发人员之间,以及团队内部进行高效、准确的沟通。良好的实现则能缩短服务上线的周期...

    IT大咖说
  • 腾讯信鸽集成

    现在移动推送很多大厂都在做,腾讯信鸽跟个推、极光、友盟比算是比较晚的一个了。 但这并不妨碍我用它。

    从今若
  • Java 集合系列09: Map架构

    前面,我们已经系统的对List进行了学习。接下来,我们先学习Map,然后再学习Set;因为Set的实现类都是基于Map来实现的(如,HashSet是通过Hash...

    好好学java
  • React Relay 实现

    1.query的命名: 注意query前缀保持和js文件名一致,ex: App.js 命名 AppRankTypeQuery 2.schema.graph...

    从今若

扫码关注云+社区

领取腾讯云代金券