【问题标题】:RESTful API and real life exampleRESTful API 和现实生活中的例子
【发布时间】:2016-09-22 13:03:46
【问题描述】:

我们有一个 Web 应用程序(AngularJS 和 Web API),它具有非常简单的功能 - 显示作业列表并允许用户选择和取消选定的作业。

我们正在尝试使用我们的 API 遵循 RESTful 方法,但这就是令人困惑的地方。

找工作很容易——简单GET: /jobs

我们应该如何取消选中的作业?请记住,这是我们需要实施的作业的唯一操作。 (对我来说)最简单和最合乎逻辑的方法是将所选作业 ID 的列表发送到 API(服务器)并执行必要的程序。但这不是 RESTful 方式。

如果我们要按照 RESTful 方法来做,我们需要向jobs 发送 PATCH 请求,json 类似于:

PATCH: /jobs
[
    {
      "op": "replace",
      "path": "/jobs/123",
      "status": "cancelled"
    },
    {
      "op": "replace",
      "path": "/jobs/321",
      "status": "cancelled"
    },
]

这将需要在客户端生成此 json,然后将其映射到服务器上的某些模型,解析 "path" 属性以获取作业 ID,然后进行实际取消。这对我来说似乎非常复杂和人为。

关于这种操作的一般建议是什么?当很多操作不能简单地映射到 RESTful 资源范式时,我很好奇人们在现实生活中会做什么。

谢谢!

【问题讨论】:

    标签: rest api asp.net-web-api restful-architecture


    【解决方案1】:

    如果取消作业您的意思是删除它,那么您可以使用DELETE 动词:

    DELETE /jobs?ids=123,321,...
    

    如果取消工作是指将一些状态字段设置为已取消,那么你可以使用PATCH动词:

    PATCH /jobs
    Content-Type: application/json
    [ { "id": 123, "status": "cancelled" }, { "id": 321, "status": "cancelled" } ]
    

    【讨论】:

    【解决方案2】:

    POST 业务流程

    POST 在这种情况下通常是一个被忽视的解决方案。将资源视为名词是 REST 中一种有用且常见的做法,因此,POST 通常从 CRUD 语义映射到“CREATE”操作 - 但是HTTP Spec for POST 没有这样的要求:

    POST 方法请求目标资源根据资源自己的特定语义处理请求中包含的表示。例如,POST 用于以下功能(以及其他功能):

    • 向数据处理进程提供数据块,例如输入 HTML 表单的字段;
    • 将消息发布到公告板、新闻组、邮件列表、博客或类似的文章组;
    • 创建一个尚未被源服务器识别的新资源;和
    • 将数据附加到资源的现有表示中。

    在你的情况下,你可以使用:

    POST /jobs/123/cancel
    

    并将其视为第一个选项的示例 - 向数据处理过程提供数据块 - 类似于使用 POST 提交表单的 html 表单。

    使用此技术,您可以在正文中返回作业表示和/或返回 303 See Other 状态代码,并将 Location 设置为 /jobs/123

    有些人抱怨这看起来“太 RPC”——但如果你阅读规范,没有什么不是 RESTful 的——而且我个人觉得这比试图找到从 CRUD 操作到实际业务的任意映射要清楚得多进程。

    理想情况下,如果您关心遵循 REST 规范,则应通过作业表示中的超媒体链接将取消操作的 URI 提供给客户端。例如如果您使用HAL,您将拥有:

    GET /jobs/123
    {
        "id": 123,
        "name": "some job name",
        "_links" : {
           "cancel" : {
               "href" : "/jobs/123/cancel"
           },
           "self" : {
               "href" : "/jobs/123"
           }
        }
    }
    

    然后客户端可以获取“取消”rel 链接的href,并发布到它以实现取消。

    将流程视为资源

    另一个选项是,根据在您的域中是否有意义,将“取消”设为名词并将数据与其关联,例如取消者、取消时间等 - 如果作业可能会被取消、重新打开和再次取消,因为更改的历史记录可能是有用的业务数据,或者如果取消行为是一个异步过程,需要随时间跟踪取消请求的状态。使用这种方法,您可以使用:

    POST /jobs/123/cancellations
    

    这将“创建”一个作业取消 - 然后您可以进行如下操作:

    GET /jobs/123/cancellations/1
    

    返回与取消相关的数据,例如

    {
        "cancelledBy": "Joe Smith",
        "requestedAt": "2016-09-01T12:43:22Z",
        "status": "in process"
        "completedAt": null
    }
    

    和:

    GET /jobs/123/cancellations
    

    返回已应用于作业的取消集合及其当前状态。

    【讨论】:

      【解决方案3】:

      示例 1:让我们将其与现实世界的示例进行比较:您去一家餐厅坐在餐桌旁,然后选择需要 ABC。你会让你的服务员上来记录你想要的东西。你告诉他你想要ABC。因此,您正在请求 ABC,服务员用 ABC 回复他,他进入厨房并为您提供食物。在这种情况下,谁是您和厨房之间的接口,谁是您的服务员。他有责任将您的请求带到厨房,确保完成,并且您知道一旦准备好,他就会回复您。

      示例 2:我们可以关联的另一个重要示例是旅行预订系统。例如,以 Kayak 最大的在线订票网站为例。你输入你的目的地,一旦你选择了日期并点击搜索,你得到的是来自不同航空公司的结果。 Kayak 如何与所有这些航空公司沟通?这些航空公司一定有一些方法实际上是在向 Kayak 提供某种程度的信息。这就是所有的谈话,它是通过 API 的

      示例 3:现在打开 UBER 看看。网站加载后,您可以登录或继续使用 Facebook 和 Google。在这种情况下,谷歌和 Facebook 也暴露了一定程度的用户信息。 UBER 和谷歌/Facebook 之间已经达成了一项协议。这就是它允许您注册 Google/Facebook 的原因。

      【讨论】:

        【解决方案4】:
        PUT /jobs{/ids}/status "cancelled"
        

        例如

        PUT /jobs/123,321/status "cancelled"
        

        如果您想取消多个作业。请注意,作业 ID 不得包含逗号字符。

        https://www.rfc-editor.org/rfc/rfc6570#page-25

        【讨论】:

        • 1,2,3,4??是一种玩笑吗?
        • @LautaroCozzani 为什么会是个玩笑?这是一个完全有效的集合资源标识符。当 id 包含 , 字符时,它唯一可能出现的问题。
        • @LautaroCozzani 我为你不知道 URI 模板的情况添加了一个链接。
        猜你喜欢
        • 1970-01-01
        • 2011-12-13
        • 2012-01-27
        • 2011-07-16
        • 2010-11-23
        • 2016-10-26
        • 1970-01-01
        • 1970-01-01
        • 2016-12-26
        相关资源
        最近更新 更多