Restful API规范实践

文章介绍了构建RESTAPI时涉及的HTTP协议要点,包括HTTP动词(GET、POST、PUT、DELETE)与CRUD操作的对应,资源的定义及其层次结构,以及如何设计URI。强调使用名词而非动词,利用HTTP方法来操作资源,并给出了RESTfulAPI设计的一系列最佳实践,如使用复数名词,使用查询字符串处理复杂参数,以及分页、排序和字段选择等。
摘要由CSDN通过智能技术生成

1 REST 之上 HTTP 知识

在构建良好的 REST API 之前,我们了解一些 HTTP 协议的基础知识。
但就 REST API 设计本身,所涉及到的 HTTP 知识要点包含以下几条:

  1. HTTP 中包含动词(或方法): GET、POST、PUT、DELETE 是最常用的。
  2. REST 是面向资源的,一个资源被一个 URI 所标识,如 /users/。
  3. 端点(endpoint),一般指动词与 URI 的组合,如 GET: /users/。
  4. 一个端点可以被解释为对某种资源进行的某个动作。如 POST: /articles 可能代表“创建一个新的 article”。
  5. 在业务领域,可以将动词和 CRUD(增删查改)关联起来:GET 代表查,POST代表增,PUT 代表改,DELETE 代表删。

2 资源的定义

面向资源的 API 通常被构建为资源层次结构,其中每个节点是一个“简单资源”或“集合资源”。

一个集合资源包含相同类型的资源列表。 例如,一个用户拥有一组联系人。

资源具有一些状态和零个或多个子资源。 每个子资源可以是一个简单资源或一个集合资源。

3 URI定义

a、用名词代替动词表示资源

使用名词会让你的 API 更简洁,URL 数目更少,请看如下示例。

#不要这么设计
/getAllUsers
/getAllExternalUsers
/createUser
/updateUser

#更好的设计
GET /users
GET /users?state=external
POST /users
PUT /users/56

b、(不要出现动词作为资源)用 HTTP 方法操作资源

使用 URL 指定你要用的资源。使用 HTTP 方法来指定怎么处理这个资源。使用四种 HTTP 方法 POST、GET、PUT、DELETE 可以提供 CRUD 功能(创建,获取,更新,删除)。

  • 获取:使用 GET 方法获取资源。GET 请求从不改变资源的状态。无副作用。GET 方法是幂等的。GET 方法具有只读的含义。
  • 创建:使用 POST 创建新的资源。
  • 更新:使用 PUT 更新现有资源。
  • 删除:使用 DELETE 删除现有资源。
  • 当 HTTP 提供的 GET、DELETE、POST、PUT 方法不够表示出接口能力含义时,会需要自定义动作(参考表格:自定义方法)。

2 个 URL 乘以 4 个 HTTP 方法就是一组很好的功能。

POST(创建)
GET(读取)
PUT(更新)
DELETE(删除)
标准方法HTTP 方法举例描述举例示例
getGET单个资源查询/v1.0/users/{user_id}
listGET资源分页、列表查询/v1.0/users?page_no=1&page_size=10
createPOST资源创建/v1.0/users
updatePUT资源修改/v1.0/users/{user_id}
deleteDELETE资源删除/v1.0/users/{user_id}
自定义方法POST自定义不要出现动作为资源/v1.0/msgs/{msg_id}/actions-push
GET 准则
  • 返回的资源对象名称必须映射到网址中
  • 请求参数应该映射到 query 参数中
  • 不可包含body
PUT 准则
  • 返回的资源对象名称必须映射到网址中
  • 包含资源的请求必须映射到 body 中,其余放到 query 中
  • 响应消息必须是资源本身
  • 必须保证幂等
DELETE 准则
  • 返回的资源对象名称必须映射到网址中
  • 请求参数应该映射到 query 参数中
  • 不可包含 body
  • 物理删除应该返回空,逻辑删除应该返回删除后状态
POST 准则
  • 返回的资源对象名称必须映射到网址中
  • 请求参数应该映射到 query 参数中
  • 请求可以包含 resource_id 字段,允许客户端定义
  • 响应消息必须是资源本身
  • 可以使用名词-动词来自定义方法

Restful API实践总结

1、推荐使用复数名词

尽量使用复数,但是避免复数和单数名词混合使用,这显得非常混乱且容易出错。

#推荐
/users
/users/21

#不推荐
/user
/user/21

2、对可选的、复杂的参数,使用查询字符串(?)

#不推荐:
GET /users
GET /external_users
GET /internal_users
GET /internal_and_seniorusers


#推荐(为了让 URL 更小、更简洁。为资源设置一个基本 URL,将可选的、复杂的参数用查询字符串表示)
GET /users?state=internal&maturity=senior

3、为关系使用子资源

常见的情况下,资源需要多级分类,因此很容易写出多级的 URL,如下有一些正例和反例。

#正例(获取已发布的文章)
GET /articles?published=true

#反例(获取已发布的文章)
GET /articles/published

#正例
#Returns a list of drivers for car 711
GET /cars/711/drivers

#Returns driver #4 for car 711
GET /cars/711/drivers/4 

4、使用用简明扼要的英文

#正例
/v1.0/config
#反例
/v1.0/configuration

5、必须使用中划线 - 连接组合词

#正例
/v1.0/users-password/1

#如下都是反例
/v1.0/userspassword/1/
/v1.0/usersPassword/1/
/v1.0/users password/1/

6、为集合提供过滤

为所有字段或者查询语句提供独立的查询参数。

#Returns a list of red cars
GET /cars?color=red 

#Returns a list of cars with a maximum of 2 seats
GET /cars?seats<=2 

7、为集合提供排序

允许跨越多字段的正序或者倒序排列:
这种更易读(参考了各大厂风格)

GET /cars?sort=name:desc,model:asc

8、为集合提供字段选择

一些情况下,只需要在列表中查询几个有标识意义的字段,不需要服务端把所有字段的值都请求出来,需要支持 API 选择查询字段的能力,也可提高网络传输性能和速度。

GET /cars?fields=manufacturer,model,id,color

9、为集合提供分页

提供两种分页查询实践。

---
范例1(普通分页,如MySQL数据源)
---
#入参
page_no   Integer  页码
page_size Integer  分页大小 
[其他查询条件参数...]

#出参
has_more  Boolean 是否有下一页
total     Long    总数
list      List<T> 数据集合  


---
范例2(滚动分页,如ES数据源)
---
#入参
page_size     Integer  分页大小
last_row_key  String   上一页返回的分页标识
[其他查询条件参数...]

#出参
has_more  		Boolean 是否有下一页
total     		Long    总数
last_row_key	String   上一页返回的分页标识
list     		List<T> 数据集合 

10、入参放uri,还是url后面?

#如果是资源主体,资源递进关系,放 uri 中
 GET:/v1.0/users/{user_id}

#如果是对资源有一个筛选能力,放 query 中
GET:/v1.0/users?user_ids=xxx

11、uri 正例和反例示例

#示例1(获取设备列表)
//正例
GET:/v1.0/devices?product_id=xxx

//反例(查询必须用 GET)
POST:/v1.0/devices  
BODY:{"productId":"xxx"}

//反例(属于资源主体属性的查询过滤条件不要体现在路径内,建议放到 query 中)
GET:/v1.0/devices/products/{product_id}

#示例2(修改设备信息)
//正例
PUT:/v1.0/devices/{device_id}

//反例(修改必须用 PUT)
POST:/v1.0/devices/{device_id}  
BODY:{}

//反例(资源尽量用复数表示)
PUT:/v1.0/device/{device_id}

#示例3(修改app群组分组定时)
//正例
POST:/v1.0/app-groups/modify-timers 
BODY {"app_group_id":"","category":"","group_id":""}

//反例(资源层级最好不要超过两级;语义复杂的建议使用 POST)
PUT:/v1.0/app-groups/{app_group_id}/timers/categories/{category}/groups/{group_id}/status

#示例3(触发app上报)
//正例
POST:/v1.0/apps/{app_id}/trigger-report

//反例(自定义语义用 POST 来表示; {动词-名词} 格式来表示。)
PUT:/v1.0/apps/{app_id}/trigger-report
POST:/v1.0/apps/{app_id}/report/trigger
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不甩锅的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值