Search code examples
restcomplextypehttp-deletehttp-put

Pass complex object to delete method of REST Service


I have REST service that manage the resource EASYPAY.. In this moment this service exposes 3 different methods:

  1. Get a EasyPay request (GET);
  2. Insert a Easypay request (POST);
  3. Update a Easypay request (PUT).

Whe I inserto or update a request I must insert also a row on a trace table on my database.

Now I have to delete a Easypay request and I must add also a row on the trace table. I wanted to use the DELETE HTTP verb, but I saw that with delete I cannot pass a complex object but just the ID of the request to delete. I cannot use the PUT HTTP verb because I have already used it, and in any case it would not be conceptually correct... I do not want to do more that one call from client to server (one for delete the request, the other one to add a row in the trace table).. So I do not know how to solve the problem.

EDIT

I try to explain better... I have a web site that is deployed on two different server. One for front-end and one for Back-end. Back-end expose some REST services just for front-end and it has no access to internet (just to intranet). The customer that access the web site can do a payment via a system called XPAY and it works really similar to paypal (XPAY is just another virtual POS). So when the customer try to do a payment, I save some information on the database + I trace the attempt of the payment, then he is redirected to XPAY. There, he can do the payment. At the endy XPAY return to the web-site (the front end) communicating us the result of the payment. The result is in the URL of payment, so i must take all the information in the url and send them to the back-end. According to the result, I must update (if result is ok) or delete (if result is ko) the information I saved before and write a row on the trace table.

What do you suggest?

Thank you


Solution

  • There are actually a couple of ways to solve your problem. First, REST is just an architectural style and not a protocol. Therefore REST does not dictate how an URI has to be made up or what parameters you pass. It only requires a unique resource identifier and probably that it should be self-descriptive, meaning that a client can take further actions based on the returned content (HATEOAS, included links even to itself and proper content type specification).

    DELETE

    As you want to keep a trace of the deleted resource in some other table, you can either pass data within the URI itself maybe as query parameter (even JSON can be encoded in order to be passed as query parameter) or use custom HTTP headers to pass (meta-)information to the backend.

    Sending a complex object (it does not matter if it is XML or JSON) as query parameter may cause certain issues though as some HTTP frameworks limit the maximum URI size to roughly 2000 characters. So if the invoked URI exceeds this limit, the backend may have trouble to fulfill the request.

    Although the hypertext transfer protocol does not define a maximum number (or size) of headers certain implementations may raise an error if the request is to large though.

    POST

    You of course also have the possibility to send a new temporary resource to the backend which may be used to remove the pending payment request and add a new entry to the trace table.

    According to the spec:

    The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

    This makes POST request feasible for short living temporary resources which trigger some processing on the server side. This is useful if you want to design some queue-like or listener system where you place an action for execution into the system. As a POST request may contain a body, you can therefore send the POS response within the body of the POST request. This action request can then be used to remove the pending POS request and add a new entry to the trace table.

    PATCH

    Patch is a way a client can instruct a server to transform one or more resources from state 1 to state 2. Therefore, the client is responsible for breaking down the neccessary actions the server has to take to transform the resources to their desired state while the server tries to execute them. A client always works on a known state (which it gathered at some previous time). This allows the client to modify the current state to a desired state and therefore know the needed steps for the transition. As of its atomic requirements either all instruction succeed or none of them.

    A JSON Patch for your scenario may look like this:

    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" ] }
    ]
    

    where 12345 is the ID of the actual easypay request and POSAnswerHere should be replaced with the actual response of the POS service or what the backend furthermore expects to write as a trace.

    The If-Match header in the example just gurantees that the patch request is executed on the latest known state. If in the meantime a further process changed the state (which also generates a new If-Match value) the request will fail with a 412 Precondition Failed failure.

    Discussion

    While DELETE may initially be the first choice, it is by far not the best solution in your situation in my opinion as this request is not really idempotent. The actual POS entity deletion is idempotent but the add of the trace is not as multiple sends of the same request will add an entry for each request (-> side-effect). This however contradicts the idempotency requirements of the DELETE operation to some degree.

    POST on the otherhand is an all-purpose operation that does not guarantee idempotency (as PATCH does not gurantee either). While it is mainly used to create new resources on the server side, only the server (or the creators of that server-application) know what it actually does with the request (though this may be extended to all operations). As there are no transactional restrictions adding the trace might succeed while the deletion of the pending request entity might fail or vice versa. While this may be handled by the dev-team, the actual operation does not give any gurantees on that issue. This may be a major concern if the server is not in your own hands and thus can not be modified or checked easily.

    The PATCH request, which is still in RFC, may contain therefore a bit more semantic then the POST request. It also specifies the ability to modify more then one resource per request explicitely and insist on atomicity which also requires a transaction-like handling. JSON Patch is quite intuitive and conveys a more semantics then just adding the POS response to a POST entity body.

    In my opinion PATCH should therefore be prefered over POSTor DELETE.