一些基于rest的服务使用不同的资源uri进行更新/获取/删除和创建。如
Create -在某些地方使用/resource(单数)使用POST方法使用/resources(复数) 更新-使用PUT方法使用/resource/123 Get -使用Get方法使用/resource/123
我对这个URI命名约定有点困惑。我们应该用复数还是单数来创建资源?决定的标准应该是什么?
一些基于rest的服务使用不同的资源uri进行更新/获取/删除和创建。如
Create -在某些地方使用/resource(单数)使用POST方法使用/resources(复数) 更新-使用PUT方法使用/resource/123 Get -使用Get方法使用/resource/123
我对这个URI命名约定有点困惑。我们应该用复数还是单数来创建资源?决定的标准应该是什么?
当前回答
对我来说,复数操作集合,而单数操作集合中的项。
集合允许使用GET / POST / DELETE方法
项允许GET / PUT / DELETE方法
例如
POST on /students将在学校增加一名新学生。
DELETE on /students将删除学校中的所有学生。
DELETE /student/123将从学校删除学生123。
这可能感觉不重要,但一些工程师有时会忘记id。如果路由总是复数并执行DELETE,可能会意外擦除数据。而在奇异点上缺少id则会返回404路由。
为了进一步扩展示例,如果API应该公开多所学校,那么如下所示
DELETE on /school/abc/students将删除学校abc中的所有学生。
选择正确的词语有时本身就是一个挑战,但我喜欢保持语汇的多样性。例如cart_items或cart/items感觉正确。相反,删除购物车,删除的是购物车对象本身,而不是购物车中的物品;)。
其他回答
使用/resources的前提是它表示“所有”资源。如果执行GET /resources,则可能返回整个集合。通过发布到/resources,您将添加到集合中。
但是,单个资源在/resource上可用。如果执行GET /resource请求,则可能会出错,因为这个请求没有任何意义,而/resource/123则完全有意义。
使用/resource而不是/resources类似于使用文件系统和文件集合,/resource是包含单独的123,456个文件的“目录”。
没有对错之分,你喜欢什么就去做什么。
尽管最流行的做法是使用复数的RESTful api,例如/api/resources/123,但有一个特殊的情况,我发现使用单数名称比使用复数名称更合适/更具表现力。这是一对一关系的例子。特别是如果目标项是一个值对象(在领域驱动设计范例中)。
让我们假设每个资源都有一个一对一的accessLog,它可以被建模为一个值对象,即不是实体,因此没有ID。它可以表示为/api/resources/123/accessLog。通常的动词(POST、PUT、DELETE、GET)可以恰当地表达意图,以及关系确实是一对一的事实。
以下是Roy Fielding关于“基于网络的软件架构的架构风格和设计”的论文,这句话你可能会感兴趣:
资源是概念上的映射 到一组实体,而不是与中任何特定点的映射对应的实体 时间。
作为一个资源,映射到一组实体,对我来说,使用/product/作为访问一组产品的资源,而不是/products/本身,似乎不符合逻辑。如果需要特定的产品,则访问/products/1/。
作为进一步的参考,这个来源有一些关于资源命名约定的单词和例子:
https://restfulapi.net/resource-naming/
最重要的事情
当你在接口和代码中使用复数时,问问你自己,你的约定是如何处理这些词的:
/pants, /eye-glasses——是单数还是复数? /radii -你知道它的唯一路径是/radius还是/radix吗? /index -你知道它的复数路径是/indexes或/indexes或/indexes吗?
理想情况下,约定的规模应该没有不规则性。英语复数就不会这样,因为
它们也有例外,比如某物被称为复数形式,以及 没有简单的算法可以从一个词的单数中得到一个词的复数,从复数中得到一个词的单数,或者判断一个未知名词是单数还是复数。
这也有缺点。我脑海中最突出的是:
The nouns whose singular and plural forms are the same will force your code to handle the case where the "plural" endpoint and the "singular" endpoint have the same path anyway. Your users/developers have to be proficient with English enough to know the correct singulars and plurals for nouns. In an increasingly internationalized world, this can cause non-negligible frustration and overhead. It singlehandedly turns "I know /foo/{{id}}, what's the path to get all foo?" into a natural language problem instead of a "just drop the last path part" problem.
与此同时,一些人类语言甚至没有名词的单数形式和复数形式。他们还行。你的API也可以。
在这个问题上有很好的讨论点。在我的经验中,命名约定或者更确切地说,没有建立本地标准是许多长夜待命、头痛、危险的重构、可疑的部署、代码审查辩论等等的根本原因。特别是当它决定事情需要改变,因为一开始就没有充分考虑到。
一个实际问题跟踪了关于这个问题的讨论:
https://github.com/kubernetes/kubernetes/issues/18622
在这个问题上看到分歧是很有趣的。
我的观点是,当你考虑用户、帖子、订单、文档等常见实体时,你应该始终将它们视为实际实体,因为这是数据模型的基础。这里不应该混淆语法和模型实体,这将导致其他方面的混淆。然而,一切都是黑白的吗?确实很少这样。环境真的很重要。
当你想获取系统中用户的集合时,例如:
GET /user ->用户实体集合
GET /user/1 ->实体资源user:1 .单击“确定”
说我想要一个实体user的集合和说我想要users的集合都是有效的。
GET /users ->实体用户集合
GET /users/1 ->实体用户资源:1 .单击“确定”
从这里你可以说,从用户集合中,给我user /1。
但如果你分解用户的集合……它是一个实体的集合,其中每个实体都是一个User实体。
您不会说实体是用户,因为单个数据库表通常是用户的单个记录。但是,我们这里讨论的是基于rest的服务,而不是数据库ERM。
但这只适用于名词区分清楚的用户,而且很容易掌握。然而,当一个系统中有多种相互冲突的方法时,事情就会变得非常复杂。
事实上,这两种方法在大多数情况下都是有意义的,除了少数情况下英语就像意大利面条一样。它似乎是一种迫使我们做出许多决定的语言!
简单的事实是,无论你决定什么,你的意图要一致且合乎逻辑。
在我看来,在这里和那里混合是一个糟糕的方法!这会悄悄地引入一些可以完全避免的语义歧义。
看似单一的偏好:
https://www.haproxy.com/blog/using-haproxy-as-an-api-gateway-part-1/
这里也有类似的讨论:
https://softwareengineering.stackexchange.com/questions/245202/what-is-the-argument-for-singular-nouns-in-restful-api-resource-naming
这里最重要的常数是,这似乎确实取决于某种程度的团队/公司文化偏好,根据更大的公司指南中的细节,这两种方式都有许多优点和缺点。谷歌不一定是正确的,因为它是谷歌!这适用于任何指导方针。
不要把你的头埋在沙子里,不要把你的整个理解系统松散地建立在轶事例子和观点上。
你有必要为每件事建立坚实的推理吗?如果它适合你、你的团队和你的客户,并且对新手和经验丰富的开发者(如果你是在团队环境中)有意义,那就很好。