【问题标题】:How do you model complex operations in REST?您如何在 REST 中为复杂的操作建模?
【发布时间】:2014-01-18 05:38:18
【问题描述】:

我正在开发一款在线游戏,其中的角色可以针对其他对象和角色执行复杂的动作。我正在构建一个 REST API,并且在尝试遵循一些最基本的标准时遇到了很多麻烦。我知道 REST 并不总是答案,但出于各种原因,使用 REST 对我来说是有意义的,因为 API 的其余部分都在适当地使用它。

这里有一些棘手的例子:

GET /characters/bob/items 这将返回 Bob 携带的一组物品。

我需要对这些项目执行各种“操作”,而我很难将其建模为“资源”。

以下是一些潜在的操作,具体取决于项目的性质: 扔,吃,丢,抱

这很复杂,因为这些“操作”只适用于某些项目。例如,你不能吃剑。此外,“吃”本质上具有“删除”资源的副作用。使用“throw”也可以“删除”资源。使用“drop”可以将资源“转换”为另一种资源类型。 “投掷”要求我提供“位置”。 'Hold' 要求我提供哪只手来握住物品。那么如何将这些操作建模为资源呢?它们都不是“相似的”,因为它们都需要不同的参数并导致完全不同的行为。

目前,我有一个“操作”资源,可以将这些任意操作发布到。但这感觉太 RPC 和非标准化/可发现:

POST /actions/throw { 字符ID:5, 项目ID:10, ×:100, 是:150 }

【问题讨论】:

    标签: json api rest architecture hateoas


    【解决方案1】:

    我尽量坚持使用资源和 GET/POST/PUT/PATCH/DELETE,但基本动词倾向于直接映射到 CRUD 调用。如果没有其他信息,通常无法映射其他更复杂的操作。

    专注于资源,我可能会做这样的事情(向资源发布消息):

    POST /characters/bob/items/{bombId}?action=throw
    POST /characters/bob/items/{foodId}?action=eat
    POST /characters/bob/items/{potionId}?action=add&addedItem={ingredientId}
    

    当操作不适合该项目时返回错误。

    【讨论】:

    • 我不太确定我是否理解这种方法。我在用这种类型的 POST 修改什么“状态”/“表示”/“资源”?这感觉就像 RPC,因为查询参数最终决定了预期 POST 的“模式”。
    • 您的资源是正在使用的对象(即您正在修改的对象)。不要将 action 参数视为查询——我将其视为替换动词。 HTTP/REST 不提供动词 EAT,但 action=eat 试图对其进行建模。我认为复杂的、多资源的消息很难很好地建模。我会说“POST /actions/throw”对我来说更像 RPC。
    • @MikeDunker:您可以创建资源(集合)meals / eatingsPOST 新项目,而不是创建新动词,即:POST /characters/bob/eatings{item: X}。或者您可以创建更通用的operations 资源,然后使用{name: 'eat', item: X} 创建POST /characters/bob/operations
    【解决方案2】:

    如果我希望资源在保持 RESTful 的同时“执行复杂操作”,我会向资源发布一个复杂的文档来描述我想要发生的事情。 (复杂的文档可以是 XML、JSON 或任何数量的其他格式。)这与更常见的将 POST 映射为“创建子资源”的模式有些不同,但 POST 的含义是“do 由正文内容定义的非幂等动作”。这非常适合您的追求。

    作为 HATEOAS 发现原则的一部分,当您获取稍后将发布到的资源时,返回的部分文档应该说明这些复杂的操作文档是什么以及它们应该发送到哪里。从逻辑上讲,请考虑填写表单并提交(即使“表单”实际上是 JSON 文档或类似内容中的插槽)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多