REST API的命名以及最佳实践

目录

什么是资源

单个资源和资源集合

最佳实践

使用名词来代表资源

文档

集合

存储资源

命名规则的一致性

在资源前使用"/"来表示资源的层级关系

不要在资源后加“/”

使用"-"来增加可读性

不要使用下划线"_"

请使用小写字母

请不要加扩展名

不要使用增删改查

使用查询参数来过滤资源

在URI中不要使用动词


设计一个健壮,良好的API不仅体现了开发者的功底,也符合架构的最佳实践。本篇将讨论在设计REST API中命名中规则和最佳实践。

什么是资源

资源是什么呢?资源是REST中信息的关键抽象。在REST中任何可以被命名的信息都可以被称为资源。比如:实体、对象、文档、图像、实体集合、服务等。

资源是和状态相关的,任何一个特定时间点的资源都有属于自己的资源状态。这些状态是由数据、描述数据的元数据和超媒体链接组成。

单个资源和资源集合

资源可以是单个的,也可以是一个集合,比如products就是一个资源集合,与之对应的一个product就是一个单个资源。

/products			// 集合资源
/products/{id}		// 单个资源

 集合资源通常用复数形式,它相当于资源管理器中的一个目录文件夹,里面可以存放多个资源,客户端可以通过调用接口向其中添加/更新/删除资源。

单个资源也可以包含资源集合,这样可以很直观的定位资源。

/products/{id}/features		// 产品对应的特征集合
/products/{id}/features/{featureId}		// 产品对应的特征

最佳实践

使用名词来代表资源

RESTful 的URI应该是一个名词而不是一个动词,因为名词和资源都有特征,而动词没有。所以我们应该通过名词来代表资源,并可以对资源有各种操作。

文档

一个文档资源简单的理解可以是一条数据库记录,在REST中,可以将其理解为在资源集合下的一个资源。文档的状态可以理解为这个记录的所有key-value。

一个文档通常用名词的单数形式表示

/products/{id}/features/{featureId}
/products/{id}/features/price

集合

集合就是资源服务器的一个目录文件夹,里面可以包含多个资源,也就是资源集合。

一个集合资源通常用名词的复数形式表示

/products
/users/{id}/addresses

存储资源

存储资源通常为客户端控制的资源,客户端可以向其中添加资源,也可以获取资源,更新资源,甚至删除资源,存储资源通常不会生成新的URI,相反,当第一次存储时,每个资源都有一个URI。通常以名词的复数形式表示

/users/{id}/products

命名规则的一致性

使用一致性的命名规则将有助于降低维护成本,减少歧义,增大可读性。

在资源前使用"/"来表示资源的层级关系

/products
/products/{id}
/products/{id}/features
/products/{id}/features/{featureId}

不要在资源后加“/”

/products/{id}/features/   // 不妥

使用"-"来增加可读性

请亲爱的读者对比一下以下两者

/products/online-products/{id}
/products/onlineproducts/{id}  // 不妥

不要使用下划线"_"

大多数情况使用“-”和“_”并没有什么问题,但是对于某些主题字体或者在某些屏幕上下划线可能看不清或者被隐藏掉。

请使用小写字母

请不要加扩展名

如果想表示这个资源的类型,可以改变API的Content-Type,这样可以更清楚如何处理请求资源体。

不要使用增删改查

URI通常用来表示某个资源,而不是对某个资源的操作,我们可以使用请求类型来表示增删改查。

GET /products/{id}
POST /products
PUT /products/{id}
DELETE /products/{id}

使用查询参数来过滤资源

通常情况,可能会有很多需求需要返回集合资源的子集,比如展示虚拟产品,自营产品..,按照商品价格排序...

/products?type=online
/products?type=online&sort=price

在URI中不要使用动词

REST通常用名词表示资源,然后我们有GET,PUT,POST,DELETE方法去操作资源,这些和使用动词几乎一致。如果我们在URI中使用动词,这更像是一个RPC接口。

POST /users/{id}/activate
POST /activatedUsers 

相较于第一个activate更像是一个RPC调用,我们可以将接口设计成/activatedUser,然后将id当作body传递,这样才更像是一个REST接口。