传递复杂对象以删除REST服务的方法

时间:2016-04-13 13:41:20

标签: rest complextype http-delete http-put

我有管理资源EASYPAY的REST服务。此时此服务公开了3种不同的方法:

  1. 获取EasyPay请求(GET);
  2. 插入Easypay请求(POST);
  3. 更新Easypay请求(PUT)。
  4. 当我插入或更新请求时,我必须在我的数据库的trace表上插入一行。

    现在我必须删除一个Easypay请求,我还必须在跟踪表上添加一行。 我想使用DELETE HTTP动词,但我看到使用delete我无法传递复杂对象,只能传递要删除的请求的ID。 我不能使用PUT HTTP动词,因为我已经使用过它,无论如何它在概念上都不正确...... 我不想做更多从客户端到服务器的一次调用(一个用于删除请求,另一个用于在跟踪表中添加一行)。 所以我不知道如何解决这个问题。

    编辑

    我试着更好地解释......我有一个部署在两个不同服务器上的网站。一个用于前端,一个用于后端。后端只为前端公开一些REST服务,它无法访问互联网(仅限内部网)。 访问该网站的客户可以通过名为XPAY的系统进行支付,它的工作方式与paypal非常相似(XPAY只是另一个虚拟POS)。 因此,当客户尝试付款时,我会在数据库中保存一些信息+我跟踪付款的尝试,然后他被重定向到XPAY。在那里,他可以付款。在Endy XPAY返回网站(前端)向我们传达付款结果。 结果是在付款的URL中,因此我必须获取URL中的所有信息并将它们发送到后端。 根据结果​​,我必须更新(如果结果没问题)或删除(如果结果是ko)我之前保存的信息并在跟踪表上写一行。

    你有什么建议?

    谢谢

1 个答案:

答案 0 :(得分:3)

实际上有几种方法可以解决您的问题。首先,REST只是一种架构风格而不是协议。因此,REST并未规定如何组成URI或传递的参数。它只需要一个唯一的资源标识符,并且它可能应该是自描述的,这意味着客户端可以根据返回的内容采取进一步的操作(HATEOAS,包括链接甚至自身和适当的内容类型规范)。

DELETE

由于您希望在其他表中保留已删除资源的跟踪,您可以将URI本身内的数据传递给查询参数(甚至可以编码JSON以便作为查询参数传递)或使用自定义HTTP标头将(元)信息传递给后端。

发送复杂对象(如果它是XML或JSON无关紧要)作为查询参数可能会导致某些问题,因为某些HTTP框架会限制maximum URI size to roughly 2000 characters。因此,如果调用的URI超出此限制,后端可能无法满足请求。

虽然超文本传输​​协议没有定义标题certain implementations may raise an error if the request is to large的最大数量(或大小)。

POST

您当然也可以向后端发送新的临时资源,该资源可用于删除待处理的付款请求并向跟踪表添加新条目。

根据spec

  

POST方法执行的操作可能不会产生可由URI标识的资源。在这种情况下,200(OK)或204(No Content)是适当的响应状态,具体取决于响应是否包括描述结果的实体。

这使得POST请求对于短生存临时资源是可行的,这会触发服务器端的一些处理。如果要设计一些类似队列或侦听器的系统,并将执行操作放入系统,这将非常有用。由于POST请求可能包含正文,因此您可以在POST请求的正文中发送POS响应。然后,可以使用此操作请求删除挂起的POS请求,并向跟踪表添加新条目。

PATCH

修补程序是客户端可以指示服务器将一个或多个资源从状态1转换为状态2的一种方式。因此,客户端负责分解服务器必须采取的必要操作,以将资源转换为所需的资源服务器尝试执行它们时的状态。客户端始终处于已知状态(之前收集的某个状态)。这允许客户端将当前状态修改为期望状态,因此知道转换所需的步骤。至于其原子要求,要么所有指令都成功,要么都不成功。

您的方案的JSON Patch可能如下所示:

PATCH /path/to/resource HTTP/1.1
Host: backend.server.org
Content-lengt: 137
Content-Type: application/json-patch+json
If-Match: "abc123"

[
    { "op": "remove", "path": "/easyPayRequest/12345" }
    { "op": "add", "path": "/trace/12345", "value": [ "answer": "POSAnswerHere" ] }
]

其中12345是实际的easypay请求的ID,POSAnswerHere应该替换为POS服务的实际响应或者后端还希望写为跟踪的内容。

示例中的If-Match标题只是保证补丁请求在最新的已知状态下执行。如果在此期间另一个进程更改了状态(也会生成新的If-Match值),则请求将失败并显示412 Precondition Failed失败。

讨论

虽然DELETE最初可能是第一选择,但在我看来,这并不是你情况下最好的解决方案,因为这个请求并不是真正的幂等。实际的POS实体删除是幂等的,但跟踪的添加不是因为同一请求的多个发送将为每个请求添加条目( - >副作用)。然而,这在某种程度上与DELETE操作的幂等性要求相矛盾。

另一方面,

POST是一种通用操作,不能保证幂等性(因为PATCH也不保证)。虽然它主要用于在服务器端创建新资源,但只有服务器(或该服务器应用程序的创建者)知道它实际对请求做了什么(尽管这可以扩展到所有操作)。由于没有事务限制,添加跟踪可能会成功,而删除待处理请求实体可能会失败,反之亦然。虽然这可能由开发团队处理,但实际操作并未就此问题给予任何保证。如果服务器不在您自己手中,这可能是一个主要问题,因此无法轻易修改或检查。

仍然在RFC中的PATCH请求可能包含比POST请求更多的语义。它还指定了每个请求明确地修改多个资源的能力,并坚持原子性,这也需要类似事务的处理。 JSON Patch非常直观,只需将POS响应添加到POST实体主体,就可以传达更多语义。

因此,我认为PATCH应优先考虑POSTDELETE