我是REST的新手,我发现在一些RESTful服务中,他们使用不同的资源URI进行更新/获取/删除和创建。如
我对这个URI命名约定有点困惑。我们应该使用复数或单数来创建资源?决定时应该有什么标准?
答案 0 :(得分:528)
对我来说最好有一个可以直接映射到代码的模式(易于自动化),主要是因为代码是两端的。
GET /orders <---> orders
POST /orders <---> orders.push(data)
GET /orders/1 <---> orders[1]
PUT /orders/1 <---> orders[1] = data
GET /orders/1/lines <---> orders[1].lines
POST /orders/1/lines <---> orders[1].lines.push(data)
答案 1 :(得分:250)
我也没有看到这样做的重点,我认为这不是最好的URI设计。作为RESTful服务的用户,我希望列表资源具有相同的名称,无论我是否访问列表中的列表或特定资源。无论您是要使用列表资源还是特定资源,都应使用相同的标识符。
答案 2 :(得分:233)
使用/resources
的前提是它代表“所有”资源。如果您执行GET /resources
,则可能会返回整个集合。通过POST到/resources
,您将添加到集合中。
但是,个人资源位于/ resource。如果您执行GET /resource
,则可能会出错,因为此请求没有任何意义,而/resource/123
则非常有意义。
使用/resource
代替/resources
类似于如果您使用文件系统和文件集合并且/resource
是“目录”的方式“其中包含个人123
,456
个文件。
无论是对还是错,都选择你最喜欢的方式。
答案 3 :(得分:56)
<强>复数强>
orders/
获取订单的索引列表。例如:
GET /resources
- 返回资源项列表
POST /resources
- 创建一个或多个资源项
PUT /resources
- 更新一个或多个资源项
PATCH /resources
- 部分更新一个或多个资源项
DELETE /resources
- 删除所有资源项
对于单个资源项:
GET /resources/:id
- 根据:id
参数
POST /resources/:id
- 创建一个具有指定ID的资源项(需要验证)
PUT /resources/:id
- 更新特定资源项
PATCH /resources/:id
- 部分更新特定资源项
DELETE /resources/:id
- 删除特定资源项
对于单数的拥护者,可以这样想:你会问一个人order
并期待一件事或一系列事情吗?那么,当您键入/order
?
答案 4 :(得分:33)
<强>便利强> 事情可能有不规则的复数名称。有时他们没有。 但奇异的名字总是在那里。
e.g。 CustomerAddresses上的CustomerAddress
考虑这个相关资源。
此/order/12/orderdetail/12
比/orders/12/orderdetails/4
更具可读性和逻辑性。
资源表示像数据库表这样的实体。 它应该具有逻辑上的单数名称。 这是answer表格名称。
类总是单数。 ORM工具生成与类名相同的表。随着越来越多的工具的使用,奇异的名称正在成为一种标准。
答案 5 :(得分:28)
而最流行的做法是RESTful apis,其中使用复数,例如/api/resources/123
,有一个特殊情况,我发现使用比复数名称更恰当/富有表现力的单数名称。这是一对一关系的情况。特别是如果目标项是值对象(在Domain-driven-design范例中)。
让我们假设每个资源都有一对一accessLog
,它可以被建模为一个值对象,即不是一个实体,因此没有ID。它可以表示为/api/resources/123/accessLog
。通常的动词(POST,PUT,DELETE,GET)会恰当地表达意图以及这种关系确实是一对一的事实。
答案 6 :(得分:20)
为什么不遵循数据库表名的普遍趋势,通常接受单数形式?在那里,完成了 - 让我们重用。
答案 7 :(得分:13)
从API消费者的角度来看,端点应该是可预测的,所以
...理想地
GET /resources
应返回资源列表。 GET /resource
应返回400级状态代码。GET /resources/id/{resourceId}
应返回包含一个资源的集合。GET /resource/id/{resourceId}
应该返回一个资源对象。POST /resources
应该批量创建资源。POST /resource
应该创建一个资源。PUT /resource
应该更新资源对象。PATCH /resource
应通过仅发布已更改的属性来更新资源。PATCH /resources
应批量更新仅发布已更改属性的资源。DELETE /resources
应删除所有资源;开玩笑:400状态代码DELETE /resource/id/{resourceId}
这种方法最灵活,功能最丰富,但也是最耗时的开发方法。因此,如果您匆忙(软件开发总是这样),只需将端点resource
或复数形式resources
命名即可。我更喜欢单数形式,因为它为您提供了以编程方式进行内省和评估的选项,因为并非所有复数形式都以“#”形式结束。
说了这么多,无论出于何种原因,最常用的练习开发者选择的是使用复数形式。这最终是我选择的路线,如果你看一下像github
和twitter
这样的流行api,这就是他们所做的。
决定的一些标准可能是:
所以它取决于你。无论你做什么都是一贯的。
答案 8 :(得分:13)
我很惊讶地看到很多人会跳上复数名词的潮流。在实现单数转换为多数转换时,您是否正在处理不规则复数名词?你喜欢疼吗?
请参阅 http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm
有许多类型的不规则复数,但这些是最常见的:
名词类型形成复数示例
Ends with -fe Change f to v then Add -s
knife knives
life lives
wife wives
Ends with -f Change f to v then Add -es
half halves
wolf wolves
loaf loaves
Ends with -o Add -es
potato potatoes
tomato tomatoes
volcano volcanoes
Ends with -us Change -us to -i
cactus cacti
nucleus nuclei
focus foci
Ends with -is Change -is to -es
analysis analyses
crisis crises
thesis theses
Ends with -on Change -on to -a
phenomenon phenomena
criterion criteria
ALL KINDS Change the vowel or Change the word or Add a different ending
man men
foot feet
child children
person people
tooth teeth
mouse mice
Unchanging Singular and plural are the same
sheep deer fish (sometimes)
答案 9 :(得分:5)
我更喜欢使用单数形式来实现简单性和一致性。
例如,考虑以下网址:
/客户/ 1
我会将客户视为客户收集,但为简单起见,我们会删除收集部分。
另一个例子:
/设备/ 1
在这种情况下,设备不是正确的复数形式。因此,将其视为设备集合并简化集合,使其与客户案例保持一致。
答案 10 :(得分:5)
我的两分钱:花时间从复数变为单数或反复的方法是浪费CPU周期。我可能是老派,但在我的时间里,事情被称为相同。我如何查找有关人的方法?没有正常的表达将涵盖人和人,没有不良副作用。
英语复数可以是非常随意的,它们会不必要地阻碍代码。坚持一个命名惯例。计算机语言应该是关于数学清晰度的,而不是模仿自然语言。
答案 11 :(得分:3)
使用命名约定,通常可以安全地说&#34;只需选择一个并坚持使用#34;这是有道理的。
但是,在向许多人解释REST之后,将端点表示为文件系统上的路径是最有表现力的方式。
它是无状态的(文件存在或不存在),分层,简单和熟悉 - 您已经知道如何访问静态文件,无论是本地还是通过http。
在这种情况下,语言规则只能让你达到以下目的:
目录可以包含多个文件和/或子目录,因此其名称应为复数形式。
我喜欢那样 虽然,另一方面 - 它是您的目录,但您可以将其命名为资源或多资源&#34;如果这就是你想要的。这并不重要。
重要的是,如果你把一个名为&#34; 123&#34;在名为&#34; resourceS&#34;的目录下(产生/resourceS/123
),您无法通过/resource/123
访问它。
不要试图让它变得比它更聪明 - 根据您当前访问的资源数量从复数变为单数可能在某些方面可能在美学上令人愉悦,但它没有效果,在分层系统中没有意义。
注意:从技术上讲,您可以制作&#34;符号链接&#34;,以便/resources/123
也可以通过/resource/123
访问,但前者仍然必须存在!< / em>的
答案 12 :(得分:3)
使用单数形式,并利用例如“企业目录”。
很多东西都是这样写的:“书柜”,“狗包”,“美术馆”,“电影节”,“车位”等。
这方便地从左到右匹配网址路径。项目类型在左侧。在右侧设置类型。
GET /users
真的可以获取一组用户吗?通常不行。它获取一组包含密钥和用户名的存根。因此,它实际上并不是/users
。它是用户的索引,如果可以的话,也可以是“用户索引”。为什么不这样称呼呢?这是/user/index
。由于我们已经命名了集合类型,因此我们可以使用多种类型来显示用户的不同投射,而无需借助查询参数,例如user/phone-list
或/user/mailing-list
。
用户300呢?仍然是/user/300
。
GET /user/index
GET /user/{id}
POST /user
PUT /user/{id}
DELETE /user/{id}
最后,HTTP只能对单个请求具有单个响应。路径总是指单个事物。
答案 13 :(得分:2)
我知道大多数人在决定是使用复数还是单数。这里没有解决的问题是客户需要知道您正在使用哪一个,并且他们总是可能犯错误。这是我的建议来自的地方。
两者兼而有之?就此而言,我的意思是对您的整个API使用单数,然后创建路由以将复数形式的请求转发为单数形式。例如:
GET /resources = GET /resource
GET /resources/1 = GET /resource/1
POST /resources/1 = POST /resource/1
...
你得到了照片。没有人是错的,只需要很少的努力,而且客户永远都会做对。
答案 14 :(得分:1)
至少在一个方面,对所有方法使用复数更实用: 如果您使用Postman(或类似工具)开发和测试资源API,则在从GET切换到PUT到POST等时,您不需要编辑URI。
答案 15 :(得分:1)
两种表示都很有用。为了方便我已经使用了单数很长一段时间,变形可能很困难。我在开发严格单一的REST API方面的经验,使用端点的开发人员对结果的形状缺乏确定性。我现在更喜欢使用最能描述响应形状的术语。
如果您的所有资源都是顶级资源,那么您可以使用单一表示法。避免拐点是一个巨大的胜利。
如果您正在进行任何类型的深层链接来表示关系的查询,那么可以通过更严格的约定来帮助开发人员编写API。
我的惯例是URI中的每个深度级别都在描述与父资源的交互,而完整的URI应该隐式地描述正在检索的内容。
假设我们有以下模型。
interface User {
<string>id;
<Friend[]>friends;
<Manager>user;
}
interface Friend {
<string>id;
<User>user;
...<<friendship specific props>>
}
如果我需要提供允许客户端获取特定用户的特定朋友的经理的资源,它可能看起来像:
GET /users/{id}/friends/{friendId}/manager
以下是一些例子:
GET /users
- 列出全局用户集合中的用户资源POST /users
- 在全局用户集合中创建新用户GET /users/{id}
- 从全局用户集合中检索特定用户GET /users/{id}/manager
- 获取特定用户的经理GET /users/{id}/friends
- 获取用户的朋友列表GET /users/{id}/friends/{friendId}
- 获取用户的特定朋友LINK /users/{id}/friends
- 向此用户添加好友关联UNLINK /users/{id}/friends
- 从此用户中删除朋友关联注意每个级别如何映射到可以对其执行操作的父级。对同一个对象使用不同的父对象是违反直觉的。在GET /resource/123
检索资源并未表明应在POST /resources
答案 16 :(得分:1)
应该将路由中的ID视为与列表的索引相同,并且命名应相应进行。
numbers = [1, 2, 3]
numbers GET /numbers
numbers[1] GET /numbers/1
numbers.push(4) POST /numbers
numbers[1] = 23 UPDATE /numbers/1
但是某些资源在其路由中不使用id,因为要么只有一个,要么一个用户永远无法访问多个id,因此这些不是列表:
GET /dashboard
DELETE /session
POST /login
GET /users/{:id}/profile
UPDATE /users/{:id}/profile
答案 17 :(得分:1)
我不希望看到URL的{id}
部分与子资源重叠,因为id
从理论上讲可以是任何东西,并且会有歧义。它混合了不同的概念(标识符和子资源名称)。
类似的问题通常出现在enum
常量或文件夹结构中,其中混合了不同的概念(例如,当您拥有文件夹Tigers
,Lions
和Cheetahs
时,然后在同一级别上还有一个名为Animals
的文件夹-这没有意义,因为一个文件夹是另一个文件夹的子集。
通常,我认为端点的最后命名部分如果一次处理一个实体,则应为单数;如果处理实体列表,则应为复数。
因此,处理单个用户的端点:
GET /user -> Not allowed, 400
GET /user/{id} -> Returns user with given id
POST /user -> Creates a new user
PUT /user/{id} -> Updates user with given id
DELETE /user/{id} -> Deletes user with given id
然后有单独的资源可对用户进行查询,通常会返回一个列表:
GET /users -> Lists all users, optionally filtered by way of parameters
GET /users/new?since=x -> Gets all users that are new since a specific time
GET /users/top?max=x -> Gets top X active users
下面是处理特定用户的子资源的一些示例:
GET /user/{id}/friends -> Returns a list of friends of given user
交个朋友(很多链接):
PUT /user/{id}/friend/{id} -> Befriends two users
DELETE /user/{id}/friend/{id} -> Unfriends two users
GET /user/{id}/friend/{id} -> Gets status of friendship between two users
永远不会有任何歧义,并且资源的复数或单数命名向用户提示了他们可以期望的内容(列表或对象)。对id
没有任何限制,从理论上讲,可以使ID为new
的用户与(可能的将来)子资源名称不重叠。
答案 18 :(得分:0)
怎么样:
/resource/
(不是/resource
)
/resource/
意味着它是一个包含“资源”的文件夹,这是一个“资源”文件夹。
我也认为数据库表的命名约定是相同的,例如,一个名为“ user”的表是一个“ user table”,其中包含一个名为“ user”的东西。
答案 19 :(得分:0)
结帐 Google 的API Design Guide: Resource Names,以获取其他命名资源的信息。
简而言之:
|--------------------------+---------------+-------------------+---------------+--------------|
| API Service Name | Collection ID | Resource ID | Collection ID | Resource ID |
|--------------------------+---------------+-------------------+---------------+--------------|
| //mail.googleapis.com | /users | /name@example.com | /settings | /customFrom |
| //storage.googleapis.com | /buckets | /bucket-id | /objects | /object-id |
|--------------------------+---------------+-------------------+---------------+--------------|
答案 20 :(得分:0)
/pants
, /eye-glasses
- 那些是单数还是复数路径?
/radii
- 你是否知道它的单一路径是 /radius
还是 /radix
?
/index
- 如果复数路径是 /indexes
或 /indeces
或 /indices
,您是否一头雾水?
每当您在接口和代码中使用复数形式时,问问自己,您的约定如何处理上述单词?
理想情况下,公约应该在没有违规的情况下进行扩展。英语复数不这样做,因为
这有缺点。我头顶最突出的:
/foo/{{id}}
,获得所有 foo
的途径是什么?”变成自然语言问题,而不是“只删除最后一个路径部分”的问题。与此同时,一些人类语言甚至没有名词的单复数形式。他们管理得很好。您的 API 也可以。
答案 21 :(得分:-1)
对我来说,复数操纵集合,而单身操纵该集合中的项。
集合允许方法 GET / POST / DELETE
项目允许方法 GET / PUT / DELETE
例如
/ students 上的POST将在学校中添加一名新学生。
删除 /学生将删除学校中的所有学生。
删除 / student / 123 会删除学生123。
它可能感觉不重要但有些工程师有时会忘记id。如果路径始终为复数并执行DELETE,则可能会意外擦除数据。如果缺少单数上的id将返回未找到的404路径。
如果API应该公开多个学校,那么为了进一步扩展这个例子,那么
删除 / school / abc / students 将删除学校中的所有学生abc
。
选择正确的单词有时候本身就是一个挑战,但我喜欢为集合保留多元化。例如。 cart_items
或cart/items
感觉正确。相反,删除cart
,删除自己的购物车对象,而不删除购物车中的商品;)。
答案 22 :(得分:-3)
我更喜欢使用复数(/resources
)和单数(/resource/{id}
),因为我认为它更清楚地区分了处理资源集合和处理单一资源之间的逻辑。 / p>
作为一个重要的副作用,它还可以帮助防止有人错误地使用API。例如,考虑用户通过将Id指定为如下参数来错误地尝试获取资源的情况:
GET /resources?Id=123
在这种情况下,我们使用复数版本,服务器很可能会忽略Id参数并返回所有资源的列表。如果用户不小心,他会认为呼叫成功并使用列表中的第一个资源。
另一方面,使用单数形式时:
GET /resource?Id=123
服务器很可能会返回错误,因为没有以正确的方式指定Id,并且用户必须意识到出了问题。