json REST:用一个请求更新多个资源 - 它是标准的还是要避免的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32098423/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
REST: Updating Multiple Resources With One Request - Is it standard or to be avoided?
提问by Martin Kersten
A simple REST API:
一个简单的 REST API:
- GET: items/{id} - Returns a description of the item with the given id
- PUT: items/{id} - Updates or Creates the item with the given id
- DELETE: items/{id} - Deletes the item with the given id
- GET: items/{id} - 返回具有给定 id 的项目的描述
- PUT: items/{id} - 更新或创建具有给定 id 的项目
- DELETE: items/{id} - 删除具有给定 id 的项目
Now the API-extension in question:
现在有问题的 API 扩展:
- GET: items?filter - Returns all item ids matching the filter
- PUT: items - Updates or creates a set of items as described by the JSON payload
- [[DELETE: items - deletes a list of items described by JSON payload]] <- Not Correct
- GET: items?filter - 返回与过滤器匹配的所有项目 ID
- PUT: items - 更新或创建一组由 JSON 负载描述的项目
- [[ DELETE: items - 删除由 JSON 负载描述的项目列表]] <-不正确
I am now being interested in the DELETE and PUT operation recycling functionality that can be easily accessed by PUT/DELETE items/{id}.
我现在对可以通过 PUT/DELETE items/{id} 轻松访问的 DELETE 和 PUT 操作回收功能感兴趣。
Question: Is it common to provide an API like this?
问题:提供这样的 API 是否常见?
Alternative: In the age of Single Connection Multiple Requests issuing multiple requests is cheap and would work more atomic since a change either succeeds or fails but in the age of NOSQL database a change in the list might already have happend even if the request processing dies with internal server or whatever due to whatever reason.
替代方案:在单连接的时代,多个请求发出多个请求很便宜,并且会更加原子化,因为更改要么成功要么失败,但在 NOSQL 数据库时代,即使请求处理终止,列表中的更改也可能已经发生内部服务器或其他任何原因。
[UPDATE]
[更新]
After considering White House Web Standardsand Wikipedia: REST Examplesthe following Example API is now purposed:
在考虑了白宫网络标准和维基百科:REST 示例之后,现在使用以下示例 API:
A simple REST API:
一个简单的 REST API:
- GET: items/{id} - Returns a description of the item with the given id
- PUT: items/{id} - Updates or Creates the item with the given id
- DELETE: items/{id} - Deletes the item with the given id
- GET: items/{id} - 返回具有给定 id 的项目的描述
- PUT: items/{id} - 更新或创建具有给定 id 的项目
- DELETE: items/{id} - 删除具有给定 id 的项目
Top-resource API:
顶级资源API:
- GET: items?filter - Returns all item ids matching the filter
- POST: items - Updates or creates a set of items as described by the JSON payload
- GET: items?filter - 返回与过滤器匹配的所有项目 ID
- POST:items - 按照 JSON 有效负载的描述更新或创建一组项目
PUT and DELETE on /items is not supported and forbidden.
/items 上的 PUT 和 DELETE 不受支持和禁止。
Using POST seems to do the trick as being the one to create new items in an enclosing resource while not replacing but appending.
使用 POST 似乎可以解决问题,因为它可以在封闭资源中创建新项目,而不是替换而是追加。
HTTP Semantics POSTReads:
HTTP 语义 POST读取:
Extending a database through an append operation
通过追加操作扩展数据库
Where the PUT methods would require to replace the complete collection in order to return an equivalent representation as quoted by HTTP Semantics PUT:
PUT 方法需要替换完整集合以返回HTTP Semantics PUT引用的等效表示:
A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being returned in a 200 (OK) response.
给定表示的成功 PUT 将表明对同一目标资源的后续 GET 将导致在 200 (OK) 响应中返回等效表示。
[UPDATE2]
[更新2]
An alternative that seems even more consistent for the update aspect of multiple objects seems to be the PATCH method. The difference between PUT and PATCH is described in the Draft RFC 5789as being:
对于多个对象的更新方面似乎更加一致的替代方法似乎是 PATCH 方法。PUT 和 PATCH 之间的区别在RFC 5789 草案中描述为:
The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; i.e., new resources may be created, or existing ones modified, by the application of a PATCH.
PUT 和 PATCH 请求之间的区别体现在服务器处理封闭实体以修改 Request-URI 标识的资源的方式上。在 PUT 请求中,包含的实体被认为是存储在源服务器上的资源的修改版本,并且客户端请求替换存储的版本。但是,对于 PATCH,封闭的实体包含一组指令,描述当前驻留在源服务器上的资源应如何修改以生成新版本。PATCH 方法影响由 Request-URI 标识的资源,也可能对其他资源产生副作用;即,可以通过 PATCH 的应用程序创建新资源或修改现有资源。
So compared to POST, PATCH may be also a better idea since PATCH allows an UPDATE where as POST only allows appending something meaning adding without the chance of modification.
因此,与 POST 相比,PATCH 可能也是一个更好的主意,因为 PATCH 允许更新,而 POST 只允许附加一些意味着添加而没有修改机会的内容。
So POST seems to be wrong here and we need to change our proposed API to:
所以 POST 在这里似乎是错误的,我们需要将我们提议的 API 更改为:
A simple REST API:
一个简单的 REST API:
- GET: items/{id} - Returns a description of the item with the given id
- PUT: items/{id} - Updates or Creates the item with the given id
- DELETE: items/{id} - Deletes the item with the given id
- GET: items/{id} - 返回具有给定 id 的项目的描述
- PUT: items/{id} - 更新或创建具有给定 id 的项目
- DELETE: items/{id} - 删除具有给定 id 的项目
Top-resource API:
顶级资源API:
- GET: items?filter - Returns all item ids matching the filter
- POST: items - Creates one or more items as described by the JSON payload
- PATCH: items - Creates or Updates one or more items as described by the JSON payload
- GET: items?filter - 返回与过滤器匹配的所有项目 ID
- POST: items - 按照 JSON 有效负载的描述创建一个或多个项目
- PATCH: items - 按照 JSON 有效负载的描述创建或更新一个或多个项目
采纳答案by mahemoff
You could PATCH the collection, e.g.
您可以修补集合,例如
PATCH /items
[ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ]
Technically PATCH would identify the record in the URL (ie PATCH /items/1and not in the request body, but this seems like a good pragmatic solution.
从技术上讲,PATCH 会识别 URL 中的记录(即 PATCH/items/1而不是请求正文中的记录,但这似乎是一个很好的实用解决方案。
To support deleting, creating, and updating in a single call, that's not really supported by standard REST conventions. One possibility is a special "batch" service that lets you assemble calls together:
为了支持在单个调用中删除、创建和更新,标准 REST 约定并不真正支持这一点。一种可能性是一种特殊的“批处理”服务,可让您将调用组合在一起:
POST /batch
[
{ method: 'POST', path: '/items', body: { title: 'foo' } },
{ method: 'DELETE', path: '/items/bar' }
]
which returns a response with status codes for each embedded requests:
它为每个嵌入的请求返回一个带有状态代码的响应:
[ 200, 403 ]
Not really standard, but I've done it and it works.
不是很标准,但我已经做到了并且它有效。
回答by B12Toaster
Updating Multiple Resources With One Request - Is it standard or to be avoided?
用一个请求更新多个资源 - 这是标准的还是要避免的?
Well, sometimes you simply need to perform atomic batch operations or other resource-related operations that just do not fit the typical scheme of a simple REST API, but if you need it, you cannot avoid it.
好吧,有时您只需要执行原子批处理操作或其他与资源相关的操作,这些操作只是不适合简单 REST API 的典型方案,但如果您需要它,则无法避免。
Is it standard?
它是标准的吗?
There is no universally accepted REST API standard so this question is hard to answer. But by looking at some commonly quoted api design guidelines, such as jsonapi.org, restfulapi.net, microsoft api design guideor IBM's REST API Conventions, which all do not mention batch operations, you can infer that such operations are not commonly understood as being a standard feature of REST APIs.
没有普遍接受的 REST API 标准,所以这个问题很难回答。但是通过查看一些常用的api设计指南,比如jsonapi.org、restfulapi.net、microsoft api design guide或者IBM的REST API Conventions,这些都没有提到批处理操作,可以推断出这样的操作并不普遍理解为是 REST API 的标准功能。
That said, an exception is the google api design guide which mentionsthe creation of "custom" methods that can be associated via a resource by using a colon, e.g. https://service.name/v1/some/resource/name:customVerb, it also explicitly mentions batch operations as use case:
也就是说,一个例外是 google api 设计指南,它提到了可以通过使用冒号通过资源关联的“自定义”方法的创建,例如https://service.name/v1/some/resource/name:customVerb,它还明确提到批处理操作作为用例:
A custom method can be associated with a resource, a collection, or a service. It may take an arbitrary request and return an arbitrary response, and also supports streaming request and response. [...] Custom methods should use HTTP POST verb since it has the most flexible semantics [...] For performance critical methods, it may be useful to provide custom batch methods to reduce per-request overhead.
自定义方法可以与资源、集合或服务相关联。它可以接受任意请求并返回任意响应,并且还支持流式请求和响应。[...] 自定义方法应该使用 HTTP POST 动词,因为它具有最灵活的语义 [...] 对于性能关键的方法,提供自定义批处理方法以减少每个请求的开销可能很有用。
So in the example case you provided you do the following according to google's api guide:
因此,在您提供的示例中,您根据 google 的 api 指南执行以下操作:
POST /api/items:batchUpdate
Also, some public APIs decided to offer a central /batchendpoint, e.g. google's gmail API.
此外,一些公共 API 决定提供一个中央/batch端点,例如google 的 gmail API。
Moreover, as mentionedat restfulapi.net, there is also the concept of a resource "store", in which you store and retrieve whole lists of items at once via PUT – however, this concept does not count for server-managed resource collections:
此外,正如在 restfulapi.net 上提到的,还有资源“存储”的概念,您可以在其中通过 PUT 一次存储和检索整个项目列表——但是,这个概念不计入服务器管理的资源集合:
A store is a client-managed resource repository. A store resource lets an API client put resources in, get them back out, and decide when to delete them. A store never generates new URIs. Instead, each stored resource has a URI that was chosen by a client when it was initially put into the store.
存储是客户端管理的资源存储库。存储资源允许 API 客户端放入资源、取回资源并决定何时删除它们。商店永远不会生成新的 URI。相反,每个存储的资源都有一个 URI,该 URI 在最初放入存储时由客户端选择。
Having answered your original questions, here is another approach to your problem that has not been mentioned yet. Please notethat this approach is a bit unconventional and does not look as pretty as the typical REST API endpoint naming scheme. I am personally not following this approach but I still felt it should be given a thought :)
回答了您最初的问题后,这里是另一种尚未提及的解决您的问题的方法。请注意,这种方法有点非常规,看起来不像典型的 REST API 端点命名方案那么漂亮。我个人并没有遵循这种方法,但我仍然觉得应该考虑一下:)
The idea is that you could make a distinction between CRUD operations on a resource and other resource-related operations (e.g. batch operations) via your endpoint path naming scheme.
这个想法是您可以通过端点路径命名方案区分资源上的 CRUD 操作和其他与资源相关的操作(例如批处理操作)。
For example consider a RESTful API that allows you to perform CRUD operations on a "company"-resource and you also want to perform some "company"-related operations that do not fit in the resource-oriented CRUD-scheme typically associated with restful api's – such as the batch operations you mentioned.
例如,考虑一个 RESTful API,它允许您对“公司”资源执行 CRUD 操作,并且您还希望执行一些不适合通常与 RESTful api 相关的面向资源的 CRUD 方案的“公司”相关操作——比如你提到的批量操作。
Now instead of exposing your resources directly below /api/companies(e.g. /api/companies/22) you could distinguish between:
现在,不是直接在下面公开您的资源/api/companies(例如/api/companies/22),您可以区分:
/api/companies/items– i.e. a collection of company resources/api/companies/ops– i.e. operations related to company resources
/api/companies/items– 即公司资源的集合/api/companies/ops– 即与公司资源相关的运营
For itemsthe usual RESTful api http-methods and resource-url naming-schemes apply (e.g. as discussed hereor here)
对于items通常的 RESTful api http-methods 和 resource-url 命名方案适用(例如讨论here或here)
POST /api/companies/items
GET /api/companies/items
GET /api/companies/items/{id}
DELETE /api/companies/items/{id}
PUT /api/companies/items/{id}
Now for company-related operations you could use the /api/companies/ops/route-prefix and call operations via POST.
现在对于与公司相关的操作,您可以/api/companies/ops/通过 POST使用路由前缀和调用操作。
POST /api/companies/ops/batch-update
POST /api/companies/ops/batch-delete
POST /api/companies/ops/garbage-collect-old-companies
POST /api/companies/ops/increase-some-timestamps-just-for-fun
POST /api/companies/ops/perform-some-other-action-on-companies-collection
Since POST requests do not have to result in the creation of a resource, POST is the right method to use here:
由于 POST 请求不一定会导致创建资源,因此在这里使用 POST 是正确的方法:
The action performed by the POST method might not result in a resource that can be identified by a URI. https://tools.ietf.org/html/rfc2616#section-9.5
POST 方法执行的操作可能不会产生可由 URI 标识的资源。 https://tools.ietf.org/html/rfc2616#section-9.5
回答by Kris
As far as I understand the REST concept it covers an update of multiple resources with one request. Actually the trick here is to assume a container around those multiple resources and take it as one single resource. E.g. you could just assume that list of IDs identifies a resource that contains several other resources.
据我了解 REST 概念,它涵盖了一个请求对多个资源的更新。实际上,这里的技巧是假设一个围绕这些多个资源的容器并将其作为一个单一的资源。例如,您可以假设 ID 列表标识包含多个其他资源的资源。
In those examples in Wikipediathey also talk about resources in Plural.

