子资源的 REST API 约定



假设有一个活动托管服务。主持人可以使用以下方法登录和创建活动:

POST /events创建事件

GET /events获取主机创建的所有事件

GET /events/1获取 ID 为 1 的事件(如果由主机创建,否则出错)

现在,主持人希望为来宾可以回复的活动生成批量邀请代码,并且主持人应该能够看到响应。主持人只能与来宾共享代码,不想共享活动 ID(因为它看起来不酷)

POST /events/1/invites受邀者列表以生成代码

GET /event/1/invites获取受邀者列表并查看他们的回复

GET /event/1/invites/SECRET007获取特定邀请的回复

到目前为止看起来不错,但是邀请回复的惯例是什么?

一种选择是:PUT /invites/SECRET007,但问题是它与GET对应物不匹配。

另一种选择是保留 PUT API 并更改所有其他 API 以进行邀请

POST /invites正文 : { 事件:1 ...} 带有要生成代码的受邀者列表

GET /invites?event=1获取受邀者列表并查看他们的回复

GET /invites/SECRET007获取邀请

但在这种情况下GET /invites没有意义,必须始终使用事件 id 调用它。

这里要遵循的正确约定是什么?

编辑:这里的重要要求是主持人只能在与访客共享邀请,并且访客应该只能使用该 ID 进行回复。

关于可能有帮助的事情:REST 并没有真正理解你在这里描述的"子资源"。

/invites
/invites?event=1
/invites/SECRET007

就 REST 而言,这是三个完全独立的标识符,因此是三个完全独立的资源。 资源标识符的拼写不会传达任何语义意义。 此处的关系等效于这些:

/4498232d-9bf9-4405-a94d-ed5d2cfc5551
/951139d9-d5a9-43fb-ab23-ba4b383a7a11
/6b2d8b31-981d-4128-b354-776b8375decd

您使用的路由库可能会观察到标识符路径中的相似性,并对该信息执行一些有趣的操作,但这是在"统一接口"后面做出的实现选择。

例如:

DELETE /invites

如果该请求成功,则符合 REST 标准的缓存仍将保存/invites?event=1/invites/SECRET007的副本。 标识符的层次结构没有任何意义。

这反过来意味着(a)你可以按照你喜欢的任何方式安排你的资源,(b)你可以选择任何你方便的拼写。

有许多资源">大约"相同是正常的,每个资源都有自己的标识符。 比较

  • https://stackoverflow.com/questions/57640910/rest-api-convention-for-subresource
  • https://api.stackexchange.com/2.2/questions/57640910?order=desc&sort=activity&site=stackoverflow

因此,如果你想要一个人类可以理解的资源标识符的拼写,那么你需要仔细考虑你的资源模型,以及你提供给客户的提示集合。

参见吉姆·韦伯2011年的演讲

Microsoft发布了一个复杂的文档,其中包含设置 REST API 时的指南。每个用例都没有详尽的规则,因此您必须做出自己的决定。使用 GET/POST/PUT/events等 CRUD 模式似乎是首选。

查看指南:https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#931-nested-collections-and-properties

我不知道这是否是"正确的约定",但是当我遇到类似情况时,我采取了务实的方法,并试图避免深度资源嵌套,除非绝对必要。

我确定"绝对必要"意味着子资源标识符不是全局唯一的。 例如,如果您的路径是:

/events/1/invites/1
/events/1/invites/2
/events/2/invites/1

然后,邀请 ID 本身不足以识别确切的邀请,您需要一个包含事件 ID 的复合 ID。

如果邀请 ID全局唯一的 - 而不仅仅是事件的唯一 - 那么您没有理由不能拥有根/invites资源。

/events:
get:  
description: list events
post:
description: create event
/{id}:
get: 
description: get event with id {id}
/invites:
get:
description: list all invites for an event
post:
description: create an invite for an event
/invites:
/{id}:
get: 
description: get invite with id {id}
put:
description: update invite with id {id} (record RSVP)

如果您认为这是必需的,则可以使用实质上重复的路由来访问同一资源。 例如,您可能/events/{eventId}/invites/{inviteId}/invites/{inviteId}才能访问同一邀请。如果您通过事件发现邀请,则一条路线有意义,而第二条路由是直接指向已知邀请的快捷方式。

只是我对此事的想法:)

最新更新