Rest API 设计 PUT vs PATCH

Posted

技术标签:

【中文标题】Rest API 设计 PUT vs PATCH【英文标题】:Rest API designing PUT vs PATCH 【发布时间】:2017-01-05 16:40:59 【问题描述】:

我正在开发 2 个 REST API,它们可以在我的后端编辑和暂停某些内容。 我正在使用的编辑:

PUT /video/1

开发暂停视频服务的最佳方式是什么。我应该为此使用PATCH 还是PUT?输入将只是 id。如果我使用PUT,那么如何区分编辑和暂停?如果我要开发另一个 API,例如:视频重启,我如何在 REST API 中容纳这些动词?

【问题讨论】:

REST API - PUT vs PATCH with real life examples的可能重复 我可以在您的服务的两个线程中看到相同的视频吗?如果我想暂停其中一个怎么办? 一般PUT用于替换整个资源,PATCH用于部分修改。 【参考方案1】:

仅使用 HTTP 方法来区分状态是一个糟糕的主意。你能做的是:

    引入state,然后使用PATCH改变状态:

    PATCH /vidoes/1
    
       "state": "PLAYING|PAUSED|STOPPED" // what you need here
    
    

介意don't patch like an idiot,但是像白痴一样修补是很常见的。

    引入将反映在资源上调用的操作的新端点 - 这不是完全 RESTful,但也很常见:

    POST /vidoes/1/play/
    POST /vidoes/1/stop/
    POST /vidoes/1/pause/
    

PUT 编辑当然可以,但请记住PUT 是幂等的,需要发送资源。

【讨论】:

如果使用/video/1 而不是/playback/1 会更有意义 老实说,为什么服务器要处理客户端状态?这有很多缺点。客户端应该使用部分 GET 来下载段并将它们附加到缓冲区。如果客户端想要暂停它应该简单地停止读取缓冲区并停止发送进一步的部分 GET 请求。 PUT 定义已经给出了如何解决部分更新的提示。使用 PATCH 或将大型资源解耦为较小的资源并分别更新它们。对于视频编辑系统,这对 IMO 来说也更有意义。 @RomanVottner,我想关于为什么 OP 提供的想法不好的讨论是一个不同的问题。在理想的世界中,服务器当然不应该考虑客户端的状态,但是我们并不生活在这样的世界中。基本上你是对的,但正如我所说,这不是这里讨论的内容。 PUT /videos/1/state "PAUSED" Web 套接字在这里会更好。【参考方案2】:

我不同意@Opal 在这里的回答,因此我发布了这个回答。我确实觉得您使用错误的工具(或术语)来实现您想要的。 REST 不仅仅是通过设计简洁的 URI 进行的 HTTP 调用。正如@Opal 在对他的回答的评论中提出的那样,WebSockets 可能是您正在寻找的东西,尽管 REST 也可能能够满足您的需求(就像普通的 HTTP 一样)。

暂停视频

停止视频不应该是 HTTP 服务器的任务,而是客户端的任务。通常partial GET requests 被发送到服务器,只检索资源的一部分并将它们添加到客户端读取的缓冲区中。在后面,客户端站点将发出进一步的部分请求,以在客户端读取缓冲区时保持缓冲区填充。如果客户端想要暂停,它只是停止读取缓冲区并选择性地停止向服务器发送进一步的部分 GET 请求。

这允许将实际视频传播到多个服务器上,让客户端与这些服务器中的任何一个进行对话,并且仍然可以获得正确的响应。如果服务器必须维护客户端状态,则需要确保该状态也复制到所有其他服务节点。当然,这是可能的,但也会带来更高的开销!

更新视频

当您显然创建了一个视频编辑系统时,您在这里有两个选项,PUT definiton 也建议:

通过定位一个单独标识的资源,其状态与较大资源的一部分重叠,或者使用专门为部分更新定义的不同方法(例如,@987654323 中定义的 PATCH 方法),可以实现部分内容更新@)。

将资源分成更小的资源 使用其他方法,例如PATCH

正如@Opal 在他的回答中已经指出的那样,如果您使用PATCH 部分更新资源,您不仅应该在正文中提供新内容,还应该指示服务器应该如何处理它。

不过,对于视频编辑系统来说,将资源分离为更小的资源对我来说确实更自然。视频可以看作是一系列场景,其中包含大量图片,可能还有附加的声音文件。

因此可以在伪 Json-HAL 中像这样表示电影:

Movie : 
    title: The Matrix,
    release_year: 1999,
    actors: [Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss, Hugo Weaving, Joe Pantoliano],
    ...
    link: 
        self: http://...,
        ...
    ,
    embedded: 
        Scenes : [
            
                description: Trinity chased by police,
                links: [
                    self: http://...,
                    video: http://.../scene01.vid
                ]
            ,
            
                description: Thomas Anderson get notified to follow the white rabbit,
                start_offset: 5091,
                end_offset: 193920,
                links: [
                    self: http://...,
                    video: http://.../scene02.vid
                ]
            ,
            ...
        ]
    

您可以单独维护每个场景,而不是将所有字节放在一个文件中。如果从场景 1 播放到场景 n,电影表示会将场景组合成完整的电影。

如果现在编辑了一个场景并且应该替换整个场景文件,则使用简单的 PUT 请求就足够了。如果您想修剪视频的前几秒或最后几秒,您可以为各个场景引入开始和停止偏移,而不是再次重新上传整个场景,而是告诉客户它应该从建议的节日开始或停止在建议的位置。

客户端可以在部分 GET 请求中使用此参数来仅检索必要的字节。然后当然应该通过 PATCH 命令修改此字段,以防止更改视频字节或其 URI。为了让客户端了解视频的总字节数,它可以首先向 URI 发出 HEAD 请求并使用从响应返回的内容长度

当然,这需要它自己的媒体类型,但这就是 REST 的真正意义所在。我不知道为什么这么多人滥用 REST 术语来表示普通的 URI 设计,或者认为当 REST 实际上并不关心 URI 布局时,一个简洁的 URI-API 更 RESTful。

【讨论】:

以上是关于Rest API 设计 PUT vs PATCH的主要内容,如果未能解决你的问题,请参考以下文章

我应该在我的 REST API 中使用 PATCH 还是 PUT?

Django REST framework框架之GET, POST, PUT, PATCH, DELETE等API请求接口设计

Mailchimp API Put 或 Patch 使用 Delphi REST

在 REST API 现实生活场景中使用 PUT 与 PATCH 方法

用于创建资源的 REST API 补丁方法

REST API 设计 - 最佳实践:链接现有子资源 [关闭]