用于从子资源列表中更新/添加/删除项目的 REST 设计 [英] REST design for update/add/delete item from a list of subresources

查看:21
本文介绍了用于从子资源列表中更新/添加/删除项目的 REST 设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当您拥有包含子资源列表的资源时,我想知道哪种最佳实践.例如,您有资源 Author,其中包含姓名、ID、生日和列表书籍等信息.此书单仅与作者有关​​.因此,您有以下场景:

  1. 您想在图书列表中添加一本新书
  2. 您想更新列表中的书名
  3. 您想从列表中删除一本书

解决方案 1

我搜索了正确的设计,并找到了多种方法.我想知道是否有设计这个的标准方法.我认为书中的设计说有以下方法:

  1. 添加:POST/authors/{authorId}/book/
  2. 更新:PUT/authors/{authorId}/book/{bookId}
  3. 删除:DELETE/authors/{authorId}/book/{bookId}

解决方案 2

我的解决方案是只有一个 PUT 方法来完成所有这 3 件事,因为书籍列表仅存在于对象 author 中,而您实际上是在更新作者.类似的东西:

PUT/authors/{authorId}/updateBookList(并在作者对象内发送整个更新的书籍列表)

我在我的场景中发现了多个错误.例如,从客户端发送更多数据,在客户端有一些逻辑,对 API 进行更多验证,并且还依赖客户端具有最新版本的图书列表.

我的问题是:这样做是反模式的吗?

情况 1. 在我的情况下,我的 API 使用另一个 API,而不是数据库.使用的 API 只有一种updateBookList"方法,所以我猜在我的 API 中也更容易复制这种行为.也是对的吗?

情况 2. 但是,假设我的 API 将使用数据库,使用解决方案 1 是否更合适?

另外,如果您能提供一些文章、书籍,您可以在其中找到类似的信息.我知道这种设计不是一成不变的,但一些指导方针会有所帮助.(示例:来自书籍 REST API 设计规则手册 - Masse - O'Reilly)

解决方案

解决方案 2 听起来很像旧式 RPC,其中调用一个方法来执行某些处理.这就像 REST 反模式,因为 REST 的重点是资源而不是方法.您可以对资源执行的操作由底层协议(在您的情况下为 HTTP)给出,因此 REST 应遵守底层协议的语义(其为数不多的约束之一).

此外,REST 并不关心您如何设置 URI,因此实际上没有 RESTful URL.对于自动化系统,遵循特定结构的 URI 与充当 URI 的随机生成的字符串具有相同的语义.尽管应用程序应该使用 rel 属性,它为 URI 提供了应用程序可以使用的某种逻辑名称,但我们是人类将意义放入字符串中.期望 URL 具有特定逻辑组合的应用程序已经与 API 紧密耦合,因此违反了 REST 试图解决的原则,即客户端与服务器 API 的解耦.

如果你想以 RESTful 的方式通过 PUT 更新(子)资源,你必须遵循 put 的语义,它基本上表明接收到的有效负载替换更新前在给定 URI 上可访问的有效负载.

<块引用>

PUT 方法请求目标资源的状态为创建替换由表示定义的状态包含在请求消息负载中.

<块引用>

...

<块引用>

POST 请求中的目标资源旨在处理根据资源自己的语义封闭表示,而 PUT 请求中的封闭表示被定义为替换目标资源的状态.因此,PUT 的意图是幂等的并且对中介可见,即使确切的效果只有源服务器知道.

关于部分更新 RFC 7231 指出部分更新可以通过使用@Alexandru 建议的 PATCH 或直接在子资源上发出 PUT 请求,其中有效负载将子资源的内容替换为有效载荷中的一个.对于包含子资源的资源,这会影响部分更新.

<块引用>

部分内容更新可以通过以与状态重叠的单独标识的资源为目标较大资源的一部分,或通过使用不同的方法已专门为部分更新定义(例如,[RFC5789]中定义的PATCH方法).

因此,在您的情况下,您可以通过 PUT 操作直接将更新后的图书收藏发送到诸如 .../author/{authorId}/books 之类的资源,其中替换旧的集合.因为这对于撰写了许多出版物的作者来说可能无法很好地扩展PATCH 可能更可取.但是请注意,PATCH 需要原子和事务行为.要么所有操作都成功,要么都不成功.如果在操作过程中发生错误,您必须退回所有已执行的步骤.

关于您对进一步文献的请求,SO 不是提出此问题的合适场所,因为这有一个自己的离题关闭/标记原因.

I would like to know which is the best practice when you are having a resource which contains a list of subresources. For example, you have the resource Author which has info like name, id, birthday and a List books. This list of books exists only in relation with the Author. So, you have the following scenario:

  1. You want to add a new book to the book list
  2. You want to update the name of a book from the list
  3. You want to delete a book from the list

SOLUTION 1

I searched which is the correct design and I found multiple approaches. I want to know if there is a standard way of designing this. I think the design by the book says to have the following methods:

  1. To add: POST /authors/{authorId}/book/
  2. To update: PUT /authors/{authorId}/book/{bookId}
  3. To delete: DELETE /authors/{authorId}/book/{bookId}

SOLUTION 2

My solution is to have only one PUT method which does all these 3 things because the list of books exists only inside object author and you are actually updating the author. Something like:

PUT /authors/{authorId}/updateBookList (and send the whole updated book list inside the author object)

I find multiple errors in my scenario. For example, sending more data from the client, having some logic on the client, more validation on the API and also relying that the client has the latest version of Book List.

My question is: is it anti-pattern to do this?

SITUATION 1. In my situation, my API is using another API, not a database. The used API has just one method of "updateBookList", so I am guessing it is easier to duplicate this behavior inside my API too. Is it also correct?

SITUATION 2. But, supposing my API would use a database would it be more suitable to use SOLUTION 1?

Also, if you could provide some articles, books where you can find similar information. I know this kind of design is not written in stone but some guidelines would help. (Example: from Book REST API Design Rulebook - Masse - O'Reilly)

解决方案

Solution 2 sounds very much like old-style RPC where a method is invoked that performs some processing. This is like a REST antipattern as REST's focus is on resources and not on methods. The operations you can perform on a resource are given by the underlying protocol (HTTP in your case) and thus REST should adhere to the semantics of the underlying protocol (one of its few constraints).

In addition, REST doesn't care how you set up your URIs, hence there are no RESTful URLs actually. For an automated system a URI following a certain structure has just the same semantics as a randomly generated string acting as a URI. It's us humans who put sense into the string though an application should use the rel attribute which gives the URI some kind of logical name the application can use. An application who expects a certain logical composition of an URL is already tightly coupled to the API and hence violates the principles REST tries to solve, namely the decoupling of clients from server APIs.

If you want to update (sub)resources via PUT in a RESTful way, you have to follow the semantics of put which basically state that the received payload replaces the payload accessible at the given URI before the update.

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.

...

The target resource in a POST request is intended to handle the enclosed representation according to the resource's own semantics, whereas the enclosed representation in a PUT request is defined as replacing the state of the target resource. Hence, the intent of PUT is idempotent and visible to intermediaries, even though the exact effect is only known by the origin server.

In regards to partial updates RFC 7231 states that partial updates are possible by either using PATCH as suggested by @Alexandru or by issuing a PUT request directly at a sub-resource where the payload replaces the content of the sub-resource with the one in the payload. For the resource containing the sub-resouce this has an affect of a partial update.

Partial content updates are possible by targeting a separately identified resource with state that overlaps a portion of the larger resource, or by using a different method that has been specifically defined for partial updates (for example, the PATCH method defined in [RFC5789]).

In your case you could therefore send the updated book collection directly via a PUT operation to something like an .../author/{authorId}/books resource which replaces the old collection. As this might not scale well for authors that have written many publications PATCH is probably preferable. Note, however, that PATCH requires an atomic and transactional behavior. Either all actions succeed or none. If an error occurs in the middle of the actions you have to role back all already executed steps.

In regards to your request for further literature, SO isn't the right place to ask this as there is an own off-topic close/flag reason exactly for this.

这篇关于用于从子资源列表中更新/添加/删除项目的 REST 设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆