一些基于rest的服务使用不同的资源uri进行更新/获取/删除和创建。如

Create -在某些地方使用/resource(单数)使用POST方法使用/resources(复数) 更新-使用PUT方法使用/resource/123 Get -使用Get方法使用/resource/123

我对这个URI命名约定有点困惑。我们应该用复数还是单数来创建资源?决定的标准应该是什么?


当前回答

这两种表示都很有用。在相当长的一段时间里,我为了方便而使用单数,屈折变化可能会很困难。根据我在开发严格的单一REST api方面的经验,使用端点的开发人员对结果可能是什么形状缺乏确定性。我现在更倾向于使用最能描述反应形式的术语。

如果您的所有资源都是顶级的,那么您可以使用单一表示。避免变化是一个巨大的胜利。

如果您正在使用任何类型的深度链接来表示关系上的查询,那么使用您的API编写程序的开发人员可以通过使用更严格的约定来获得帮助。

我的习惯是,URI中的每一层深度都描述了与父资源的交互,而完整的URI应该隐式地描述正在检索的内容。

假设我们有以下模型。

interface User {
    <string>id;
    <Friend[]>friends;
    <Manager>user;
}

interface Friend {
    <string>id;
    <User>user;
    ...<<friendship specific props>>
}

如果我需要提供一个资源,允许客户端获得特定用户的特定朋友的管理器,它可能看起来像这样:

GET /用户/ {id} /朋友/ {friendId} /经理

下面是更多的例子:

GET /users - list the user resources in the global users collection POST /users - create a new user in the global users collection GET /users/{id} - retrieve a specific user from the global users collection GET /users/{id}/manager - get the manager of a specific user GET /users/{id}/friends - get the list of friends of a user GET /users/{id}/friends/{friendId} - get a specific friend of a user LINK /users/{id}/friends - add a friend association to this user UNLINK /users/{id}/friends - remove a friend association from this user

注意每个级别是如何映射到一个可以被操作的父级的。为同一个对象使用不同的父对象是违反直觉的。在GET /resource/123处检索资源时,没有指示应该在POST /resources处创建新资源

其他回答

使用/resources的前提是它表示“所有”资源。如果执行GET /resources,则可能返回整个集合。通过发布到/resources,您将添加到集合中。

但是,单个资源在/resource上可用。如果执行GET /resource请求,则可能会出错,因为这个请求没有任何意义,而/resource/123则完全有意义。

使用/resource而不是/resources类似于使用文件系统和文件集合,/resource是包含单独的123,456个文件的“目录”。

没有对错之分,你喜欢什么就去做什么。

对于命名惯例,通常可以安全地说“只选择一个并坚持使用它”,这是有道理的。

然而,在不得不向许多人解释REST之后,将端点表示为文件系统上的路径是最具表现力的方法。 它是无状态的(文件存在或不存在),分层的,简单的,熟悉的-您已经知道如何访问静态文件,无论是本地还是通过http。

在这种情况下,语言规则只能让你达到以下效果:

一个目录可以包含多个文件和/或子目录,因此它的名称应该是复数形式。

但我喜欢妳 不过,另一方面,这是您的目录,如果您愿意,您可以将其命名为“一个资源或多个资源”。这不是真正重要的事情。

重要的是,如果您将一个名为“123”的文件放在名为“resourceS”的目录下(结果是/resourceS/123),那么您就不能期望通过/resource/123访问它。

不要试图让它变得比原来更聪明——根据你当前访问的资源数量从复数变成单数对某些人来说可能是美观的,但这并不是有效的,在一个等级系统中也没有意义。

注意:技术上,你可以创建“符号链接”,这样/resources/123也可以通过/resource/123访问,但前者仍然必须存在!

在这个问题上有很好的讨论点。在我的经验中,命名约定或者更确切地说,没有建立本地标准是许多长夜待命、头痛、危险的重构、可疑的部署、代码审查辩论等等的根本原因。特别是当它决定事情需要改变,因为一开始就没有充分考虑到。

一个实际问题跟踪了关于这个问题的讨论:

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

这里最重要的常数是,这似乎确实取决于某种程度的团队/公司文化偏好,根据更大的公司指南中的细节,这两种方式都有许多优点和缺点。谷歌不一定是正确的,因为它是谷歌!这适用于任何指导方针。

不要把你的头埋在沙子里,不要把你的整个理解系统松散地建立在轶事例子和观点上。

你有必要为每件事建立坚实的推理吗?如果它适合你、你的团队和你的客户,并且对新手和经验丰富的开发者(如果你是在团队环境中)有意义,那就很好。

从API使用者的角度来看,端点应该是可预测的

在理想的情况下……

GET /resources should return a list of resources. GET /resource should return a 400 level status code. GET /resources/id/{resourceId} should return a collection with one resource. GET /resource/id/{resourceId} should return a resource object. POST /resources should batch create resources. POST /resource should create a resource. PUT /resource should update a resource object. PATCH /resource should update a resource by posting only the changed attributes. PATCH /resources should batch update resources posting only the changed attributes. DELETE /resources should delete all resources; just kidding: 400 status code DELETE /resource/id/{resourceId}

这种方法最灵活,功能最丰富,但开发起来也最耗时。因此,如果您很着急(软件开发总是这样),只需命名您的端点资源或复数形式的资源。我更喜欢单数形式,因为它让你可以选择内省和编程计算,因为不是所有的复数形式都以's'结尾。

说了这么多,不管出于什么原因,最常用的实践开发人员选择使用复数形式。这是我最终选择的路线,如果你看看流行的api,如github和twitter,这就是他们所做的。

决定的一些标准可以是:

我的时间限制是什么? 我将允许我的消费者做哪些操作? 请求和结果有效负载是什么样子的? 我是否希望能够在代码中使用反射并解析URI ?

所以这取决于你。无论你做什么都要坚持。

我的观点是:那些把时间从复数变成单数或者反过来的方法是在浪费CPU周期。我可能是个老派,但在我那个时代,类似的东西都是一样的。如何查找有关人员的方法?任何正则表达式都不能同时覆盖person和people而没有不良的副作用。

英语复数可以是非常随意的,它们不必要地妨碍代码。坚持一个命名约定。计算机语言应该是关于数学的清晰性,而不是关于模仿自然语言。