混合使用REST API的复数和单数形式来表示不同的资源?

10
REST API 的复数形式更自然和常用,例如 /api/users/api/users/123
但对于某些资源来说,这种方法可能并不自然,例如:
  • /api/login - 登录特定的用户
  • /api/profile - 获取已登录用户的个人资料
在我的应用中,这些资源永远不会用于多个对象/模型。
另一方面,我读到混合使用单数和复数形式的资源名称并不是好的做法(http://pages.apigee.com/web-api-design-ebook.html)。
所以我在考虑该怎么做:
  1. 全部使用单数
  2. 全部使用复数(包括一些愚蠢的形式,如 /api/logins
  3. 不一致地使用复数形式,除了一些特殊的资源,如 /api/login/api/profile,它们始终只用于一个对象/模型。
哪种方式更好?

我遵循与数据库表相同的规则:单数。它是产品表,而不是产品表。你可以得到一个产品或一组产品。你不需要处理名词的格变化;你可以得到一个实体或一组实体。 - David Betz
4个回答

8
没有严格的指导方针来定义RESTful API,但我读到的最多的是应该以常识为上。因此,选项3:“在几乎所有资源中使用复数形式,除了一些特殊的资源,如 /api/login 或 /api/profile,这些资源总是与一个对象 / 模型一起使用。” 是最合理的选择。当你想“我需要资源X,这个URL会是什么样子?”时,你应该总是能够猜测出URL。

6

我并不是说我更喜欢复数形式,但如果您使用复数形式,可以通过以下方式来解决特殊的单数形式:

GET /api/forms/login 是HTML登录表单。从这个角度来看,login 是表单集合中一个表单的ID。

POST /api/forms/login 用于提交登录表单。

GET /api/users/{id}/profile 检索指定用户的配置文件。这对很多情况都适用,但对于匿名站点来说可能不适用,因为即使在查看其配置文件时用户的身份应该保持隐藏,也可能会遗漏他们的用户ID和真实姓名。

GET /api/profiles/{id} 将配置文件实体与用户ID分离开来,适用于匿名站点。

或者,您可以编写 GET /api/users/current/profileGET /api/sessions/current/profile ,像您发布的内容一样省略特定的ID,因为服务器将回复与当前用户相关的内容。


3

在我参与的一些项目中,我看到了一个趋势:对于大多数常见操作,Singular 看起来更加友好。例如,您可以为用户资源设置以下端点:

GET /user  --> retrieves all users
GET /user/{id} --> retrieves a user with the given id
POST /user --> inserts a new user (the user object will come in the request body)
PUT /user/{id} --> updates a user with the given id (the user object will come in the request body)
DELETE /user/{id} --> deletes the user with the given id

这些是常见的操作,当您有批量插入/更新/删除操作时,最好使用复数形式。

POST /users  (the user objects will come in the request body)
PUT /users/{listOfIds}  (the user objects will come in the request body)
DELETE /users/{listOfIds}

GET /user 和 GET /users 是同义词,这两者都可以接受查询参数来精确筛选结果,例如:

GET /users?status=active

为什么不使用 GET /users 来检索所有用户? - Ian Vaughan
是的,在所提到的方法中,GET /users 应该被用作 GET /user 的同义词,我只是添加了那个注释。 - raspacorp

2

REST(表现层状态转移)基本上是针对单个实体进行CRUD操作的。因此,在这种情况下,使用单数更有意义。但是,如果您需要获取列表,则使用复数更有意义。例如:

如果您想获取用户,则使用/api/user/{id}

但是,如果您想获取用户列表,则使用/api/users


1
事实上的标准是使用GET /entity?filter=whatever来处理多个实体,使用GET /entity/{id}来处理单个实体。你的实体没有格变化的要求;你可以得到单数实体或实体集/列表/系列。它并不是“entities”本身,而是一个实体集、列表或系列。 - David Betz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接