Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appending to a resource's attribute RESTfully

Tags:

rest

This is a follow up to Updating a value RESTfully with Post

How do I simply append to a resource's attribute using REST. Imagine I have customer.balance and balance is an int. Let' say I just want to tell the server to append 5 to whatever the current balance is. Can I do this restfully? If so, how?

Keep in mind that the client doesn't know the customer's existing balance, so it can't just

  1. get customer
  2. customer.balance += 5
  3. post customer

(there would also be concurrency issues with the above.)

like image 460
pondermatic Avatar asked Oct 15 '09 23:10

pondermatic


People also ask

Can I use GET instead of put post to make a new resource?

5) Mention whether you can use GET request instead of PUT to create a resource? No, you are not supposed to use PUT for GET. GET operations should only have view rights, while PUT resource is used for updating a data.

Can we use Put method to create a resource?

The HTTP PUT request method creates a new resource or replaces a representation of the target resource with the request payload.

What is resource method in REST api?

A resource in REST is a similar Object in Object Oriented Programming or is like an Entity in a Database. Once a resource is identified then its representation is to be decided using a standard format so that the server can send the resource in the above said format and client can understand the same format.

Which of the following HTTP method is used to create a resource?

The HTTP POST method is often used while creating a resource in a collection when the final resource URL is not known.


1 Answers

Simple, slightly ugly:

This is a simpler variation of my answer to your other question.

I think you're still within the constraints of REST if you do the following. However, I'm curious about what others think about this situation as well, so I hope to hear from others.

Your URI will be:

/customer/21/credits

You POST a credit resource (maybe <credit>5</credit>) to the URI, the server can then take the customer's balance and += it with the provided value. Additionally, you can support negative credits (e.g. <credit>-10</credit>);

Note that /customer/21/credits doesn't have to support all methods. Supporting POST only is perfectly acceptable.

However, this gets a little weird if credits aren't a true resource within your system. The HTTP spec says:

If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

Technically you're not creating a resource here, you're appending to the customer's balance (which is really an aggregate of all previous credits in the system). Since you're not keeping the credit around (presumably), you wouldn't really be able to return a reference to the newly "created" credit resource. You could probably return the customer's balance, or the <customer> itself, but that's a bit unintuitive to clients. This is why I think treating each credit as a new resource in the system is easier to work with (see below).

My preferred solution:

This is adapted from my answer in your other question. Here I'll try to approach it from the perspective of what the client/server are doing:

  • Client:

    1. Builds a new credit resource:

      <credit>
        <amount>5</amount>
      </credit>
      
    2. POSTs resource to /customer/21/credits

      POSTing here means, "append this new <credit> I'm providing to the list of <credit>s for this customer.

  • Server:

    1. Receives POST to /customer/21/credits
    2. Takes the amount from the request and +=s it to the customer's balance
    3. Saves the credit and its information for later retrieval
    4. Sends response to client:

      <credit href="/customer/21/credits/credit-id-4321234">
        <amount>5</amount>
        <date>2009-10-16 12:00:23</date>
        <ending-balance>45.03</ending-balance>
      </credit>
      

This gives you the following advantages:

  • Credits can be accessed at a later date by id (with GET /customer/21/credits/[id])
  • You have a complete audit trail of credit history
  • Clients can, if you support it, update or remove credits by id (with PUT or DELETE)
  • Clients can retrieve an ordered list of credits, if you support it; e.g. GET /customer/21/credits might return:

    <credits href="/customer/21/credits">
       <credit href="/customer/21/credits/credit-id-7382134">
         <amount>13</amount>
         ...
       </credit>
       <credit href="/customer/21/credits/credit-id-134u482">
         ...
       </credit>
       ...
    </credits>
    
  • Makes sense, since the customer's balance is really the end result of all credits applied to that customer.
like image 54
Rob Hruska Avatar answered Sep 30 '22 19:09

Rob Hruska