一些基于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感觉正确。相反,删除购物车,删除的是购物车对象本身,而不是购物车中的物品;)。
其他回答
这两种表示都很有用。在相当长的一段时间里,我为了方便而使用单数,屈折变化可能会很困难。根据我在开发严格的单一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处创建新资源
从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 ?
所以这取决于你。无论你做什么都要坚持。
为了简单和一致性,我更喜欢使用单数形式。
例如,考虑以下url:
/客户/ 1
我将把客户视为客户集合,但是为了简单起见,集合部分被删除了。
另一个例子:
/设备/ 1
在这种情况下,equipment不是正确的复数形式。因此,为了简单起见,将其视为设备集合和删除集合,使其与客户案例一致。
使用单数,并利用英语惯例,如:“商业目录”。
很多东西都是这样读的:“书柜”、“狗窝”、“美术馆”、“电影节”、“汽车场”等等。
这方便地从左到右匹配url路径。左边的项目类型。在右侧设置类型。
GET /users真的获取过一组用户吗?不是很经常。它获取一组存根,其中包含一个密钥,也许还有一个用户名。所以它不是/users。它是一个用户索引,或者你可以称之为“用户索引”。为什么不这么叫呢?它是/user/index。由于我们已经命名了set类型,我们可以有多个类型来显示用户的不同投影,而无需求助于查询参数,例如user/phone-list或/user/mail -list。
那么用户300呢?仍然是/user/300。
GET /user/index
GET /user/{id}
POST /user
PUT /user/{id}
DELETE /user/{id}
最后,HTTP对单个请求只能有一个响应。路径总是指一个单数的东西。
尽管最流行的做法是使用复数的RESTful api,例如/api/resources/123,但有一个特殊的情况,我发现使用单数名称比使用复数名称更合适/更具表现力。这是一对一关系的例子。特别是如果目标项是一个值对象(在领域驱动设计范例中)。
让我们假设每个资源都有一个一对一的accessLog,它可以被建模为一个值对象,即不是实体,因此没有ID。它可以表示为/api/resources/123/accessLog。通常的动词(POST、PUT、DELETE、GET)可以恰当地表达意图,以及关系确实是一对一的事实。