【问题标题】:Custom action in RESTful serviceRESTful 服务中的自定义操作
【发布时间】:2012-04-23 11:07:54
【问题描述】:

一段时间以来,我一直在阅读有关 RESTful 服务的文章,并且我了解对 RESOURCES 使用 VERBS 的重要性。

但有一件事我无法理解。如果我们需要调用不属于 CRUD 的某个操作会发生什么?

例如,假设我想做一只猫跳。我们应该使用哪种格式?

以下是 RESTful 的吗?

http://host/cats/123/jump

【问题讨论】:

    标签: web-services rest uri


    【解决方案1】:

    如果cats/123 代表一个资源,那么可以这样想:该资源可以有许多 状态(吃、走、睡、跳跃、小便、.. .)。当您使用 REST 架构风格设计 API 时,您希望允许客户端应用程序向将更改其状态的资源发出允许的请求。

    cats/123 的上下文中,您可以通过一系列将导致资源状态更改的POST 请求来执行此操作。利用 REST 中的超媒体功能,您可以创建如下所示的请求和响应流程。请注意,允许的链接会随着对 POST 的响应而改变。此外,客户端应用程序将编码到 Links 数组中包含的属性,而不是 Href 属性中包含的实际 URI。

    请求:

    GET cats/123
    

    回复:

    {
        "Color" : "black",
        "Age"   : "2",
        "Links":[
        {
            "Food":"kibbles",
            "Method":"POST",
            "Href":"http://cats/123",
            "Title":"Feed the cat"
        },
        {
            "Scare":"yell real loud",
            "Method":"POST",
            "Href":"http://cats/123",
            "Title":"Scare the cat"
        }]
    }
    

    请求:

    POST cats/123
    
    {
        "Food":"kibbles"
    }
    

    回复:

    {
        "Color" : "black",
        "Age"   : "2",
        "Tummy" : "full"
        "Links":[
        {
            "Sleep":"lap",
            "Method":"POST",
            "Href":"http://cats/123",
            "Title":"Pet the cat"
        },
        {
            "Scare":"yell real loud",
            "Method":"POST",
            "Href":"http://cats/123",
            "Title":"Scare the cat"
        }]
    }
    

    【讨论】:

    • +1。谢谢。但我认为我们应该使用 PUT 而不是 POST 来更新资源?我读到 POST 应该用于创建?
    • 不幸的是,关于 REST 架构风格的讨论(“争论”)围绕着对 HTTP 规范及其包含的定义的理解展开。简而言之,HTTP spec 表示 PUT 方法是一种将 整个 资源表示(客户端更新的实体)发送到服务器的方式,因此它可以替换资源的当前表示,假设客户端有最新版本。在问题中,您的“操作”是请求状态转换,而不是用更新的版本大规模替换资源。
    • {Ran out of space:)} 此外,POST 是一种可接受的使资源表示从一种状态转换到另一种状态的方式。
    • 我认为这是一个很好的答案。我只想补充说,有理论,然后人们必须实际与您的 RestAPI 互操作。并非所有库/系统都支持所有 HTTP 动词。所以在野外,我发现最好坚持使用 GET、POST、DELETE(如果你真的需要它)和 PUT(如果你真的需要它)。
    • 此答案中的示例 API 不限制使用哪些 HTTP 方法。您可以限制您设计的 API 仅支持这些方法。我回答的关键点是,实现 Fielding 的 REST 的 API 应该为 API 客户端提供与服务器交互的方法,而无需将操作耦合到硬编码的 URL。在示例 API 中,客户端代码将使用 Links 数组中的对象。自 2012 年以来,已经定义了像 HAL 这样的 JSON 规范,它们比我创建的示例更有用。
    【解决方案2】:

    对于纯粹的 Restful 设计,我会推荐类似的东西:

    POST /cats/123/actions
    

    带有主体(动作的类型在请求中定义:

    {
        "actionType": "jump",
        "customActionParameter": "some value"
    }
    

    但这将是一个矫枉过正。 所以我发现关注Google Api Design Guide for Custom Methods 更容易:

    POST /cats/123:jump
    

    这是谷歌在其云基础设施 API 中使用的方法

    【讨论】:

    • 您的第一个建议是更好的答案。 URI 标识资源,而不是方法。正确性现在可能看起来有点矫枉过正,但它将为您提供灵活、可扩展的设计,使您能够在未来轻松扩展您的 API。回到最初的问题,更好的解决方案是“名词化”该方法,然后将生成的名词视为子资源。因此/cats/123/jumps。想想 ID 为 123 的猫的跳跃。
    • 我喜欢引用的google api设计指南。
    【解决方案3】:

    不要将 HTTP 动词与您域的状态机转换或操作混为一谈。

    Stripe 的 invoice workflow 提供了一个很好的示例,说明如何以一种安静的方式表示状态转换或域操作。

    您的域模型上的操作很可能通过对状态或状态字段的修改(PUT 或 PATCH)来表示,这将触发您自己代码的状态机中的工作流。例如,在您的示例中,跳跃动作也可能导致与 3x 步数相同的状态,因此它可能是对高度或高度字段的修改。然后,您的代码可能会实现某种类型的工作流管理或状态机,然后您可以根据请求的状态更改发出自己的事件和验证规则,而不是基于为实现它而执行的“操作”。

    【讨论】:

      【解决方案4】:

      游戏晚了,但是因为 REST 是关于资源状态的,所以这也是可以接受的,如果有点冗长的话。这用形容词或名词替换了动词(经常与@developerjack 指出的 HTTP 动词混为一谈)。

      • POST /cats/123/states/jumping,或
      • POST /jumpingcats/123

      这种语法对于有限的自然状态集可能更有意义。例如,我以前做过这样的调度程序:

      • POST /scheduler/states/stopped(停止调度程序)
      • POST /scheduler/states/started(启动调度程序)
      • POST /scheduler/jobs/123/paused(暂停作业)
      • POST /scheduler/jobs/123/resumed(恢复工作)

      【讨论】:

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