【问题标题】:REST API convention for subresource子资源的 REST API 约定
【发布时间】:2019-12-29 15:24:09
【问题描述】:

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

POST /events 创建活动

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

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

现在主持人想要为客人可以回复的活动生成批量邀请码,并且主持人应该能够看到回复。主持人只能分享给客人分享代码,不想分享活动ID(因为看起来不太酷)

POST /events/1/invites 带有生成代码的受邀者列表

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

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

目前看起来不错,但邀请 RSVP 的约定是什么?

一个选项是:PUT /invites/SECRET007,但问题是它与它的 GET 对应项不匹配。

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

POST /invites body : { event:1 ...} 带有生成代码的受邀者列表

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

GET /invites/SECRET007 获得邀请

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

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

编辑:这里的重要要求是主机只能与客人共享邀请,并且客人应该能够仅使用该 ID 回复。

【问题讨论】:

    标签: rest api microservices


    【解决方案1】:

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

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

    【讨论】:

    • 这是有道理的,除非您考虑到访客只能使用邀请 ID 来回复的奇怪要求。他们没有事件 ID。
    【解决方案2】:

    关于可能有帮助的事情:REST 并不真正理解您在此处描述的“子资源”方式。

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

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

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

    您使用的 routing 库可能会观察到标识符路径的相似性,并使用该信息做一些有趣的事情,但这是在“统一接口”背后做出的实现选择。

    例如:

    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

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

    Jim Webber's 2011 talk

    【讨论】:

      【解决方案3】:

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

      我确定“绝对必要”是指子资源标识符不是全局唯一的。例如。如果您的路径是:

      /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} 来访问同一个邀请。如果您是通过活动发现邀请,则一条路线是有意义的,而第二条路线是直接通往已知邀请的快捷方式。

      只是我对此事的看法:)

      【讨论】:

        猜你喜欢
        • 2016-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多