More HTTP Methods

Updating a Resource

Now that we've worked through fetching and creating products, it's time to cover making changes to a product that already exists. Suppose we have just found out the price for one of the products in the system (Purple Pen 2.0) is too low. We need to update this product's price to $1.50. While we're at it, we need to also change the name to be more eye catching to drive up sales.

Let's take a look at the current state of that product and see what we need to change. We could look back to see what the id of that product is by scrolling back in the terminal (or going back a few pages in this book), but it is just as easy to fetch all of the products and take a look at what is there. On a system with a lot of data this wouldn't be practical, but it will be fine in this case since the web store only has a handful of products.

$ http GET book-example.herokuapp.com/v1/products
HTTP/1.1 200 OK
Connection: close
Content-Length: 284
Content-Type: application/json
Date: Thu, 02 Oct 2014 04:46:05 GMT
Status: 200 OK

[
    {
        "id": 1,
        "name": "Red Pen",
        "price": 100,
        "sku": "redp100"
    },
    {
        "id": 2,
        "name": "Blue Pen",
        "price": 100,
        "sku": "blup100"
    },
    {
        "id": 3,
        "name": "Black Pen",
        "price": 100,
        "sku": "blap100"
    },
    {
        "id": 4,
        "name": "Purple Pen",
        "price": 100,
        "sku": "purp100"
    },
    {
        "id": 5,
        "name": "Purple Pen 2.0",
        "price": 100,
        "sku": "purp101"
    }
]

It looks like the product that needs to be updated has an id of 5. Making a change to this product is going to be very similar to creating a product, with two main differences:

  • Using PUT as the HTTP method instead of POST
  • Using the product's path instead of the product collection path (e.g. /products/1 instead of /products)

PUT is the correct HTTP method for updating the value of a resource and sending all of its values back to the server. PUT tells the server to put this resource in this place. According to the HTTP spec, PUT requests must take a complete representation of the resource being updated. This means that if a parameter was required to create the resource, it is required to be sent in any PUT requests modifying that resource. This also means that any parameter left out of a PUT request is assumed to have an empty value (usually null or nil). Most APIs don't strictly follow this requirement, however, and provide a much simpler behavior by updating any parameters sent in a PUT request, and not modifying any other parameters that are already on the resource. This is technically the behavior of another HTTP method, PATCH, which we won't get into in this book as it is new and not yet widely used.

The web store follows the PUT convention of not requiring all parameters to be sent when updating a product. Let's take advantage of this and update just the price of the product. A product's price is represented in cents, so instead of sending a value of 1.50, we will use 150 (make sure you use the correct id value at the end of the request path (/5) for the Purple Pen. Check the output you saw above -- it may not be item 5):

$ http -a admin:password PUT book-example.herokuapp.com/v1/products/5 price=150
HTTP/1.1 200 OK
Connection: close
Content-Length: 60
Content-Type: application/json
Date: Thu, 02 Oct 2014 05:41:07 GMT
Status: 200 OK

{
    "id": 5,
    "name": "Purple Pen 2.0",
    "price": 150,
    "sku": "purp101"
}

We can see from the response that the name and sku of the product remain unchanged and the price has been updated to 150. Multiple values can be changed at once by sending them at the same time (don't forget to use the current id number):

$ http -a admin:password PUT book-example.herokuapp.com/v1/products/5 name="New and Improved Purple Pen" sku="newp100"
HTTP/1.1 200 OK
Connection: close
Content-Length: 73
Content-Type: application/json
Date: Thu, 02 Oct 2014 05:45:21 GMT
Status: 200 OK

{
    "id": 5,
    "name": "New and Improved Purple Pen",
    "price": 150,
    "sku": "newp100"
}

Fetching the product shows that the new values we have sent to the server have been stored successfully (don't forget to use the correct id):

$ http book-example.herokuapp.com/v1/products/5
HTTP/1.1 200 OK
Connection: close
Content-Length: 73
Content-Type: application/json
Date: Thu, 02 Oct 2014 05:47:26 GMT
Status: 200 OK

{
    "id": 5,
    "name": "New and Improved Purple Pen",
    "price": 150,
    "sku": "newp100"
}

Deleting a Resource

Now that the updates have been made to the New and Improved Purple Pen, it is time to remove the older product Purple Pen from our system. Deleting a resource is very similar to fetching a resource, with one difference: Using the DELETE HTTP method instead of GET. Otherwise, everything else should look very familiar. On the web store API, delete requests need to be authenticated, so those arguments to http should be included:

$ http -a admin:password DELETE book-example.herokuapp.com/v1/products/4
HTTP/1.1 204 No Content
Connection: close
Date: Thu, 02 Oct 2014 05:51:34 GMT
Status: 204 No Content

204 No Content is in the format 2xx, which means the request was processed successfully. 204 No Content is commonly used when it doesn't make sense to return anything in the response body, and deleting a resource is one such case. If there is no longer a resource at the path being accessed, there isn't anything to send back.

Although we have no reason not to trust the web store API, we can attempt to fetch the product that was just deleted to see if there is still a resource at its path:

$ http book-example.herokuapp.com/v1/products/4
HTTP/1.1 404 Not Found
Connection: close
Content-Length: 75
Content-Type: application/json
Date: Thu, 02 Oct 2014 05:56:43 GMT
Status: 404 Not Found

{
    "message": "Couldn't find WebStore::Product with 'id'=4",
    "status_code": 404
}

It looks like the product is gone, which is exactly what we would expect.

Summary

  • Use HTTP method PUT to update resources.
  • Use HTTP method DELETE to delete resources.

Now that we've gone over what web APIs do and how they operate, it is time to apply these concepts to a real API.