REST URI约定-创建资源时的单数或复数名称


529

我是REST的新手,我注意到在某些RESTful服务中,它们使用不同的资源URI进行更新/获取/删除和创建。如

  • 创建-使用/资源用POST方法(注意复数),使用一些地方/资源(单数)
  • 更新-使用/ resource / 123和PUT方法
  • 获取-将/ resource / 123与GET方法一起使用

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


9
遵循该主题,我在一篇文章中收集了一些著名的REST API的示例:inmensosofa.blogspot.com/2011/10/…
jjmontes

3
在阅读以下所有答案后,我得出的结论是:始终使用单数,因为(a)它是一致的;(b)它直接映射到单数类和表名;(c)一些复数名词在英语中是不规则的(不可预测的)
Will Sheppard

请参阅此答案以获取指向单个表命名约定的链接,还有另一篇文章提到了此确切问题REST API开发人员的困境 -谢谢@Sorter
Will Sheppard

Answers:


280

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

但是,单个资源位于/ resource。如果执行GET /resource,则可能会出错,因为此请求没有任何意义,而/resource/123完全有道理。

使用/resource的,而不是/resources类似于你会怎么做,如果你用,比如说,一个文件系统和文件的收集工作,/resource是“目录”与个人123456在它的文件。

不管是对还是错,都随心所欲。


55
好答案!但是Windows中的“默认”目录具有复数名称。像“程序文件”,“用户”,“文档”,“视频”等。另外,我在网站URL中经常遇到复数名称。
德米特里·贡查

50
事实上,事实上大多数人和API都采取了事实上的约定,以使其始终保持复数形式。ID指定一个资源车/ ID
PositiveGuy

205
“无论对与错,都不要错过自己最喜欢的东西。” 啊,我经常听到的那条著名的电话线让我厌倦了听到别人的声音。约定很重要,应该在社区中进行建设性的辩论,在那里可以找到更好的解决方案和良好实践。当您在URI中对资源名称使用复数形式和单数形式时,这会使您的代码和API变得复杂,因为用户和API背后的代码必须在路由和逻辑中考虑到这一点,才能区分单数还是复数,而如果您坚持使用始终保持复数形式,您没有问题。
PositiveGuy

30
@TomaszPluskiewicz您完全正确,客户不在乎。作为软件开发人员,我们应该关心-为此,我同意WTF的意见,即有关约定的建设性辩论非常有价值。
特拉维斯D

12
因此,有人可以说出一个单词的答案并接受它,这样我就不必再读一遍了。
本·乔治

623

对我来说,最好有一个可以直接映射到代码的模式(易于自动化),这主要是因为代码将是两端。

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) 

22
这样做的难易程度是由于不尊重HATEOS。复数或单数或其他形式都没关系。您应该尊重从服务器发送的uri,而不要在客户端上“积累” uri。然后,您需要为代码执行0映射。
理查德

7
@richard客户端仍然必须进行映射。在HATEOS中,它们将必须映射到表示与URI结构的关系(rel)的名称。然后,rel,方法(动词)和Content-Type组成资源媒体。这并不排除需要良好的URI设计。即使客户端可能优先使用rel名称,API的开发人员仍然需要良好的人类可读标准来进行URI构造。

4
我认为这是一个更好的答案。除了我一直更喜欢使用单数而不是复数。User.getList(),User.getById,User.delete等
东僧

3
我喜欢简单。映射的好处还在于,可以很容易地编写关于路由的文档和测试。
delos

5
这对我来说很有意义。但是,我们是一家数据库优先商店,这意味着我们从数据库架构中生成代码和api实体。数据库标准倾向于提倡单表名,因此我们继续这样做,但仍以与该答案相同的逻辑。
安德烈C.安徒生

274

我也看不到这样做的意义,而且我认为这也不是最好的URI设计。作为RESTful服务的用户,无论我访问列表还是列表中的特定资源,我都希望列表资源具有相同的名称。无论您要使用列表资源还是特定资源,都应使用相同的标识符。


69
就我而言,这是最好的答案。我感谢API设计人员喜欢说“ get resource#123”的语言正确性,但是在编写API的客户端和帮助文档时,这会带来额外的编码麻烦。(GET / api / people与GET / api / person / 123?euuuchh。)...。与其说它是“获取资源#123”,不如说成是“从资源集合中获取”匹配#123”。
沃伦·鲁马克

5
区分复数/单数资源与语言的正确性无关,而与规模有关。/ employees / 12将ID为'12'的雇员资源的子集读给我(这可能意味着任何事情,例如对最近解雇的雇员进行保存的搜索查询)。如果您以ID为'12'的员工身份阅读上述内容,您将如何表示子集?唯一的选择是通过使URI更加复杂的矿石来区分包含对象的集合与对象本身(即单数还是复数)。
Erik 2014年

9
我认为,选择/ employees / 12来代表对最近被解雇的员工(或任何子集)的搜索查询是不好的设计。如果您想代表任何种类的子集,我建议将它们本身作为资源(使用专有名称)进行介绍。
Jan Deinhard 2015年

3
这与客户的可理解性无关。这是关于使用不同的URL解决不同的问题。并且能够响应所有HTTP方法而不会发生冲突。您可以拥有作为项目集合的资源,以及代表项目本身的资源。就我所关心的而言,集合资源可能是example.org/166316e2-e1,而该集合中的一个特定项目example.org/20d68348-ccc-001c4200de。客户端不应构造URL(显然不能扩展,它不是RESTful的,这是链接关系类型的作用)。
Erik

4
如果您认为任意URL都不漂亮,请随意标识具有复数名称的集合资源和具有单数名称的单个项。如果您不喜欢英文网址,并且您的自然语言不支持这种单数/复数表示法,请使用其他方式以您喜欢的语言对其进行定义,我想所有语言都可以使您以某种方式区分“ / the-collection-of- bla / 2321”与“ bla / 61”的书面说明。在发送GET / PUT / DELETE / POST / PATCH和其他消息时,这两种不同的资源各自表示完全不同的结果。
Erik

77

复数

  • 简单 -所有网址都以相同的前缀开头
  • 逻辑 - orders/获取订单的索引列表。
  • 标准 -应用最广泛的标准,随后是绝大多数公共和私有API。

例如:

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呢?


10
单数:如果系统的一部分只有一个对象(0-1,是否存在),例如users / 1 / avatar,则可以使用单数形式来标记该单个对象(例如,avatar)-这里有更详细的示例:stackoverflow .com / a / 38296217/860099。顺便说一句-非常好的答案:)
卡米尔·基列夫斯基(KamilKiełczewski)

映射到类名和表名该怎么办?(请参阅其他答案
威尔谢泼德

@WillSheppard-类名最好以单数形式出现,而表名最好以复数形式出现。例如,Order对于一个处理引用一个顺序的对象的单个实例的类来说,它是一个好名字。OrderList是处理多个Order实例的类的名称。Orders Table是许多订单的数据库表的好名字。
Eric Knudtson

我想获取/ orders,但我只想要/ 1
Jim Smith

@ jim-smith那么您为什么不从GET / users / 1的用户集合中请求/ 1?
罗默

49

单数

便利 事物可以具有不规则的复数名称。有时他们没有一个。但是单数名称始终存在。

例如,CustomerAddress超过CustomerAddresses

考虑此相关资源。

/order/12/orderdetail/12比更具可读性和逻辑性/orders/12/orderdetails/4

数据库表

资源代表诸如数据库表之类的实体。它应该具有逻辑上的单数名称。这是表格名称的答案

类映射

类总是单数。ORM工具生成与类名称同名的表。随着越来越多的工具被使用,单数名称已成为一种标准。

阅读有关REST API开发人员困境的更多信息


39
单数名称始终存在 /clothe/12/trouser/34 :)
Gert Arnold

18
@GertArnold这个词clothe是动词。其余的API在谈论资源时通常使用名词,在描述动作时使用动词。单数形式是clout,但是过时的,很可能更适合用代替garment
Steve Buzonas

@SteveBuzonas还有裤子和太阳镜吗?
Koray Tugay

32

尽管最普遍的做法是使用复数形式的RESTful API,例如/api/resources/123,在一种特殊情况下,我发现使用单数名称比复数名称更合适/更具表达性。一对一的关系就是这种情况。特别是如果目标项目是值对象(在域驱动设计范式中)。

让我们假设每个资源都是一对一的accessLog,可以将其建模为值对象,即不是实体,因此没有ID。它可以表示为/api/resources/123/accessLog。常用动词(POST,PUT,DELETE和GET)会适当地表达意图,并且也表明这种关系确实是一对一的。


4
不错的尝试。但是最好使用“ accessLogEntries”。:-)
汤姆·罗素

8
@TomRussell为什么?这的含义很重要。我了解即使在通过标识符访问资源时,为什么还要使用复数,但是对于多对一或一对一来说,这是很容易让人误解的。考虑一个管理多地点公司员工的api。每个工作人员在一个位置工作。GET /users/123/location应该获取用户工作的位置。真的不GET /users/123/locations误导消费者吗?
卡莉·肯德尔

1
@CarrieKendall我明白你的意思了。由于accessLog被建模为属性或值,而不是实体,因此应为单数。如果您过分设计,那么日志条目将是一个实体,而您将拥有/api/accessLogEntries?resource=123
汤姆·罗素

同意,但是,我认为这确实违反了使所有事物都复数的惯例。这是一个棘手的问题。对我而言,重要的是,API应当简单明了,即文档应补充已经简单明了的实现。
卡莉·肯德尔

我不是系统或数据库人员,而是程序员,所以我喜欢一个讲故事而不是遵循惯例的API。但是,自动化文档的含义是真实的。
汤姆·罗素

26

为什么不遵循通常接受单数形式的数据库表名称的流行趋势?到那里,做完了-让我们重复使用。

表命名难题:单数与复数名称


8
Das Auto比Die Autos更好。同样,英语复数约定也不统一。
FlavorScape 2014年

7
资源名称空间是语义问题,而不是实现问题。因此,使用DB表类推并不是很幸运。同样,在使用DB-s时,您只操作表,尽管您当然可以影响内容(行),但是在REST中,没有直接操作单个资源的约束。
arpadf 2014年

3
我认为这是一个很好的类比,但是比决定采用单数还是复数更重要的一点是要与您选择的任何一个保持一致。您不会插入用户,然后从用户中选择。相同的规则应适用于REST资源-请勿根据您的工作重命名它们。
Todd Menier

3
它不仅是表名,还可以与OO中的类名相提并论(我的类称为客户而非客户)。
bytedev

在这种情况下,语义太重要了,不能简单地接受“已经定义的”趋势
Cattani Simone

19

看到如此多的人跳上复数名词带动我感到惊讶。在实现单数到复数转换时,您要注意不规则的复数名词吗?你喜欢痛苦吗?

参见 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)

5
我不明白这里的担忧。我们不应该通过编程将单数更改为复数。上述多数复数形式中的大多数都是众所周知的,因此不必担心。如果某人英语知识较差,那么他将错误地拼写您变量的任何部分。另外,按照您的逻辑,您是否还建议使用单数形式在源代码中引用集合?
kishor borate

1
有些英语单词是不规则的,甚至在盎格鲁圈内也经常出现问题,它们是常用的术语,例如索引/索引/索引,顶点/顶点/顶点,矩阵/矩阵/矩阵,半径/半径/半径等。无论如何,我都看不出使REST路径复数的意义,因为如果它们始终一致地为单数,则对所有人来说都更加明显。
该死

@kishorborate,即使对于以英语为母语的人,使用复数作为URI也更容易出错。正如damd所指出的那样,诸如索引/索引/索引的复数形式引入了更多的问题。并且有不可数名词。将不可数名词与复数混合是另一个问题。为什么使程序员更难在这些上花费更多的时间呢?我建议对所有内容使用单数形式。如果存在/ {id},则API应该返回一条记录。如果后面没有/ {id},则API应该返回该集合。
大名傅

3
@DamingFu单个资源可能并不总是具有与之关联的ID。例如。/ user / {id} / nickName不清楚,是返回昵称列表还是单个昵称列表?因此,使用复数形式的API更加直观。是的,很少有单词具有不规则的复数形式。对于正在阅读复数形式的人来说,这不是问题。仅在编写API签名时才有问题。但是这种单词的出现频率不高,而且,找到任何单词的复数形式也不费时。为了使API更加直观,这是我们应该接受的折衷方案。
kishor borate

15

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

理想地...

  1. GET /resources 应该返回资源列表。
  2. GET /resource 应该返回400级状态代码。
  3. GET /resources/id/{resourceId} 应该返回一个资源的集合。
  4. GET /resource/id/{resourceId} 应该返回一个资源对象。
  5. POST /resources 应该批量创建资源。
  6. POST /resource 应该创建一个资源。
  7. PUT /resource 应该更新资源对象。
  8. PATCH /resource 应该只发布更改的属性来更新资源。
  9. PATCH /resources 应该批量更新资源,仅发布更改的属性。
  10. DELETE /resources应该删除所有资源;只是在开玩笑:400状态码
  11. DELETE /resource/id/{resourceId}

这种方法最灵活,功能最丰富,但开发时间也最长。因此,如果您很着急(在软件开发中通常如此),只需命名端点resource或复数形式即可resources。我更喜欢单数形式,因为它可以让您选择以编程方式进行内省和评估,因为并非所有复数形式都以“ s”结尾。

综上所述,无论出于何种原因,开发人员选择的最常用的做法是使用复数形式。最终这就是我选择的路线,如果您喜欢github和一样的流行api twitter,这就是它们的作用。

决定的一些标准可能是:

  1. 我的时间限制是什么?
  2. 我将允许我的消费者执行哪些操作?
  3. 请求和结果有效载荷是什么样的?
  4. 我是否希望能够使用反射并解析代码中的URI?

因此,取决于您。无论您做什么,都要保持一致。


1
似乎选择了复数形式是因为开发人员似乎假定所有资源本质上都是某个集合的一部分。但是,“接受的约定”似乎表明POST /users应该创建一个用户,并将其添加到集合中。我不同意。POST /users应该创建一个用户列表(即使该列表为1),也POST /user应该创建一个用户。我认为没有理由不能同时存在多个资源端点和单个资源端点。他们描述了不同的行为,不应让任何人感到惊讶。
2015年

没有在路径中指定资源ID的约定吗?如果是这样,它似乎被广泛忽视。例如,POST users/<id>将创建一个新用户。
汤姆·罗素

1
@TomRussell通常由服务器创建ID,因此您尚不知道要发布的ID。
Alex

3
@TomRussell,当客户端在创建新资源时确定(一种)id时,通常会使用PUT /users/<id>代替POSTPOST解释为“将其添加到集合中,并确定ID作为其中的一部分”。PUT解释为“使用此ID更新(或添加)此资源”。有关此原理的详细说明,请参见restcookbook.com/HTTP%20Methods/put-vs-post
Jochem Schulenklopper

我不认为与Twitters API进行比较是公平的,因为它们的所有端点都使用复数形式。对于相同的元素,它们不会混合使用“复数”和“单数”。
Andrew T Finnell

7

我的两分钱:花费时间从复数变为单数或反之亦然的方法是浪费CPU周期。我可能是高中生,但是在我的时代,事物被称为相同。如何查找有关人的方法?没有规律的表达不会覆盖人和人,而不会产生不良副作用。

英文复数可以是非常任意的,它们不必要地妨碍了代码。遵守一个命名约定。计算机语言应该是数学上的清晰度,而不是模仿自然语言。


2
这解决了试图“自动生成/修改”端点的代码(有很多自以为是的库,它们假定为复数/奇异并尝试映射)。但是,这确实适用于显式选择的端点名称,而不是选择正确的词(无论其如何复数)。
user2864740

6

为了简化和保持一致性,我更喜欢使用单数形式。

例如,考虑以下URL:

/客户/ 1

我会将客户视为客户集合,但为简单起见,删除了集合部分。

另一个例子:

/设备/ 1

在这种情况下,设备不是正确的复数形式。因此,将其视为设备集合并为简单起见删除集合使其与客户案例保持一致。


2
POST / customer听起来将取代一个唯一的客户。这是我使用单一资源名称的最大遗憾。
安德鲁·T·芬内尔18'Apr

2
@ andrew-t-finnell不该POST /customer做的就是-插入一个客户吗?
donmutti

它将单个客户插入到客户集合中。POST /customer给我读,好像它是发给the客户的。不是客户的集合。但是,我会承认“ Plural”或“ Plural”不是首选。只要它们不像其他答案那样混杂。这将令人难以置信。
Andrew T Finnell

在这种情况下,“发给客户”是没有意义的。POST不会替换,它会插入。也许是POST / customer / 1,我可以看到这个难题,但是从REST的角度来看,即使这样也没有多大意义,因为您要插入什么?这将是/ customer / 1 /发票或/ customer / 1 / receipt,等等
。– damd

5

路由中的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

4

使用命名约定,通常可以说“只选一个并坚持下去”是很安全的,这是有道理的。

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

在这种情况下,语言规则只能使您达到以下目标:

目录可以包含多个文件和/或子目录,因此其名称为复数形式。

我喜欢那个。
虽然,另一方面,这是您的目录,如果需要的话,可以将其命名为“ a-resource-or-multiple-resources”。那不是真正重要的事情。

重要的是,如果将名为“ 123”的文件放在名为“ resourceS”的目录下(导致/resourceS/123),则不能期望可以通过进行访问/resource/123

不要尝试使其变得比必需的更加聪明-根据您当前正在访问的资源数量,从复数更改为单数可能在美学上令人愉悦,但这是无效的,并且在某种意义上是没有意义的等级制度。

注意:从技术上讲,您可以进行“符号链接”,因此/resources/123也可以通过进行访问/resource/123,但是前者仍然必须存在!


3

请参阅GoogleAPI设计指南:资源名称,以另一种方式命名资源。

简而言之:

  • 集合以复数命名。
  • 各个资源用字符串命名。
|--------------------------+---------------+-------------------+---------------+--------------|
| 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   |
|--------------------------+---------------+-------------------+---------------+--------------|

如果您正在考虑此主题,则值得阅读。


2

至少在一个方面,对所有方法使用复数更为实用:如果您正在使用Postman(或类似工具)开发和测试资源API,则在从GET转换为PUT再转换为POST等时,无需编辑URI。 。


1
因为Postman提供了收藏,所以这对我来说不是一个论点,因此您可以将所有资源另存为不同的收藏项目并分别进行测试。您要做的就是从集合中选择资源,而不必每次都编辑参数/方法/等。
Wirone

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


1

我知道大多数人都在决定使用复数还是单数之间。此处尚未解决的问题是客户端将需要知道您使用的是哪个客户端,并且他们总是很可能会犯错。这是我的建议的来源。

两者呢?而且,我的意思是对整个API使用单数形式,然后创建路由以将以复数形式提出的请求转发到单数形式。例如:

GET  /resources     =     GET  /resource
GET  /resources/1   =     GET  /resource/1
POST /resources/1   =     POST /resource/1
...

您得到图片。没有人是错的,付出最小的努力,客户将永远正确。


1
如果您执行302重定向,并且缓存将所有内容存储两次,则您设置的缓存错误。缓存不应该存储302重定向。
wynnset

2
如果您的客户始终使用/resources并且总是被重定向到/resource,那么您做错了。如果其他人使用您的API,则他们可以直接使用正确的URL或被重定向(有效但错误),而您打开的方式却是错误的。
maaartinus

不知道您的意思是“错”是非常主观的。这不是真的错误,因为它确实有效。
wynnset

这增加了维护成本,理解成本以及所需的代码量。
Will Sheppard '18年

1

我不希望看到{id}URL 的一部分与子资源重叠,因为从id理论上讲它可以是任何东西,并且会有歧义。它混合了不同的概念(标识符和子资源名称)。

类似的问题经常出现在enum常量或文件夹结构,不同的概念混合(例如,当你有文件夹TigersLionsCheetahs,然后又一个文件夹,名为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

永远不会有任何歧义,并且资源的复数或单数命名向用户提示了他们可以期望的内容(列表或对象)。对ids 没有任何限制,从理论上讲,可以使用户具有id new而不会与(潜在的将来)子资源名称重叠。


1

使用单数,并利用“业务目录”中的英语约定。

很多东西都是这样阅读的:“书柜”,“狗包”,“美术馆”,“电影节”,“车位”等。

这很方便地从左到右匹配网址路径。项目类型在左侧。在右侧设置类型。

难道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只能对单个请求具有单个响应。路径总是指单数。


-1

对我来说,复数操纵集合,而单数操纵集合中的项目

集合允许方法GET / POST / DELETE

项目允许方法GET / PUT / DELETE

例如

/ students上的POST 将在学校中添加一个新学生。

删除/学生将删除所有学校的学生。

/ student / 123上的DELETE 会将学生123从学校中删除。

感觉似乎并不重要,但有些工程师有时会忘记ID。如果路由始终为复数并执行了DELETE,则可能会意外擦除数据。而缺少单数形式的ID将返回未找到的404路由。

为了进一步扩展示例,假设该API应该公开多个学校,则类似

/ school / abc / students上删除将删除学校中的所有学生abc

有时候,选择正确的单词本身就是一个挑战,但是我喜欢保持集合的多元性。例如cart_itemscart/items感觉正确。相反cart,删除会删除自身的购物车对象,而不是购物车中的项目;)。


/ cart和/ cart / item是否应该拆分?然后您可以解决整个购物车(例如删除)或单个商品的问题?
罗布·格兰特

@RobertGrant难道不是“ / carts / items / 123”吗?(例如,为什么“购物车”而不是“小车”的规则是“总是复数”?)
user2864740,18年

1
我认为,如果签入生产代码能够删除所有人的购物车商品,则存在比命名约定更大的问题。他们可能会记住ID上的“ s”的可能性要小得多。
Andrew T Finnell '18 -4-3

有人会创建仅删除整个集合的端点吗?对我来说似乎非常危险,也许还有为什么REST并不真正支持批量删除。(您必须将数组包装到一个对象中)。如果我绝对需要一个端点来删除整个集合,那么我将确保URI非常独特,并且绝对不同于POST
cnps

-1

怎么样:

/resource/(不是/resource

/resource/ 表示它是一个包含“资源”的文件夹,这是一个“资源”文件夹。

而且我还认为数据库表的命名约定是相同的,例如,一个名为“ user”的表是一个“用户表”,其中包含一个名为“ user”的东西。


-2

我更喜欢同时使用复数(/resources)和单数(/resource/{id}),因为我认为它更清楚地将处理资源集合与处理单个资源之间的逻辑分开。

作为重要的副作用,它还可以帮助防止有人错误使用API​​。例如,考虑以下情况:用户通过将Id指定为这样的参数来错误地尝试获取资源:

GET /resources?Id=123

在这种情况下,如果我们使用复数版本,则服务器很可能会忽略Id参数并返回所有资源的列表。如果用户不小心,他会认为呼叫成功,并使用列表中的第一个资源。

另一方面,使用单数形式时:

GET /resource?Id=123

服务器很可能会返回错误,因为没有以正确的方式指定Id,并且用户将必须意识到某些错误。


1
你为什么在这里混成语?您在第一段中使用正确的URI表示法,然后切换到查询参数?在这里,使用查询参数获取ID为123的资源是完全不合理的。
Andrew T Finnell '18

这显然是一个错误。我已经更新了我的答案。感谢您的注意。
pberggreen

再次被否决后,我查看了自己写的内容,意识到原来的帖子是正确的。我的观点恰恰是,如果用户做错了事,那么使用复数+单数实际上会给出比仅使用复数更好的错误消息。
pberggreen

我仍然感到这令人困惑。使用复数的想法是它是一个集合。最后的数字是集合的索引。如果您自己获取/资源怎么办?同时使用复数和单数是非常令人困惑的。说/ resources / 123表示:在资源存储区中获取我的资源123。
Andrew T Finnell '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.