Tag Archives: REpresentational State Transfer

REST : RESTin’ in the RESTful World – part 1

Today I’m going to present to you the RESTful architecture. The concept is simple but often misunderstood. I’m a big fan of the idea, because it gives us both freedom and simplicity by just using the HTTP protocol.

REST stands for “REpresentational State Transfer” and is introduced in 2000 by Roy Fielding in his doctoral dissertation. I know quite a few people which think of REST as just using HTTP GET and POST requests to modify and read resources in given format. This is not REST, this is some kind of custom communication API. I was one of these people until I chose to read some books and articles for a change and it turned out to be quite refreshing… I’ll tell you about the RESTful architecture as I see it through my mind.

Imagine that the Web is an Universe. Universe composed of resources. These resources have unique identifiers and can be viewed through many different representations. For example in a list of comments, stored somewhere in the Web we have many comment resources. Every comment resource has its own URI (identifier) that points to it. The comment resource consists of an author and comment body, maybe some database ID and a time-stamp providing information about when the resource was last edited. We can add some metadata to this resource that provides information about the maximum acceptable length of a comment body…

Now we can view these resources in some representation. For example the list of the comment resources is stored in a database, but we won’t download the database file in its raw format, we will present an HTML page showing the comments, or we will return XML representation of the list, or JSON, or YAML, or some PDF. These are the representations. The server provides one or more representations of the resource for example HTML, JSON and XML. We can tell the server which representation we want to use. For example we can navigate with the browser to the URL http://forum-meddlings.rhcloud.com/comments and this will render the comment list in its HTML representation. If we navigate to http://forum-meddlings.rhcloud.com/comments.json, we will see the JSON representation of the list. Let’s use cURL:

  • curl -i http://forum-meddlings.rhcloud.com/comments
    

    This will retrieve the comment list in HTML format, the Content-Type response header value is ‘text/html;charset=utf-8’.

  • curl -i http://forum-meddlings.rhcloud.com/comments.json
    

    Now we see a JSON array containing the comments as JSON objects, the Content-Type response header value is ‘application/json;charset=utf-8’.

  • curl -i -H "Accept: application/json" \
    http://forum-meddlings.rhcloud.com/comments
    

    Again we see a JSON array containing the comments as JSON objects, the Content-Type response header value is ‘application/json;charset=utf-8’. We used the Accept request header to tell the server that we accept only JSON response.

The above conversations with the server are interesting. We want the server to Transfer to us the current State of the resource identified by the URL. We negotiate with the server for the REpresentation of the resource. This content negotiation is done by adding a format at the end of the URL or by setting the Accept request header. If the server doesn’t recognize the format it can send us HTTP 406 response (not acceptable).

We saw how we are able to view given resource state in a given representation, it is simple – we know where the resource is accessible via its URL and we request it from the server in given format via the request. But what if we want to create new resource or delete existing one or edit a resource.

The HTTP protocol has its methods (verbs). You all know about GET and POST, and maybe you know of PUT, DELETE, HEAD, TRACE and OPTIONS…

I’m going to introduce you to the REST CRUD (CREATE, READ, UPDATE, DELETE). We will use POST for creation, GET for reading, PUT for updating and DELETE for deleting resources. It is important to understand the difference between PUT and POST.
POST creates resources. It POSTs a new resource to a collection of resources; when you execute POST you don’t know what the URL of the new resource will be.
For example you have http://somewhere.com/resources and you POST a new resource to this URL, when the new resource is created it is given a new unique URL http://somwhere.com/resource/5. Now we can use PUT to update the resource located at this URL. PUT knows the URL of the resource it modifies.
So POST adds a new resource to a resource collection, creates resources, and PUT updates the resource data located at existing an URL.

Another thing about the HTTP verbs. GET, PUT and DELETE are idempotent. This means that if I execute the same PUT request one time or 100 times the result will be the same. Think about it… We modify the resource at http://somwhere.com/resource/5 setting the value ‘foo’ to ‘bar’, if we execute the same request 100 times the result we’ll be the same as the first time, a resource with attribute ‘foo’ set to ‘bar’. The same is true for DELETE – you can delete the resource one time or 100 times, in the end it will be deleted, the same as the first time. GET is reading, the same every time.
POST is another story if we POST the same resource data 5 times in the http://somewhere.com/resources collection we will have 5 different resources with the same data. Again the difference between POST and PUT, POST creates new resources with new IDS, new URLs…

I think we are ready to communicate with our RESTful API. We will create a new resource, then we will read it, we will update it and delete it. The API is simple:
– Here we have a collection of comment resources – http://forum-meddlings.rhcloud.com/comments
– Every comment resource has unique id and is located at http://forum-meddlings.rhcloud.com/comment/<id>
– When we read resources from the collection we can use their IDs to manipulate them.
– My application provides us we two representations – JSON and HTML, you can play with the HTML representation through your browser.
– Every comment has two mandatory fields – ‘author’ and comment ‘body’.

      1. Lets create a new comment; we will POST to http://forum-meddlings.rhcloud.com/comments a new comment represented as JSON data.
        We will tell the server how to parse this data by setting the request’s Content-Type header to ‘application/json’ and we will want the newly resource in JSON format, so the Accept header will be set to ‘application/json’ too:

        curl -i \
          -H "Accept: application/json" \
          -H "Content-Type: application/json" \
          -d '{"author": "meddle", "body": "My new comment!"}' \
          http://forum-meddlings.rhcloud.com/comments

        We created the new comment! Here is the response:

        HTTP/1.1 200 
        Date: Tue, 14 May 2013 13:27:56 GMT
        Server: Apache/2.2.15 (Red Hat)
        X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
        Content-Length: 69
        Status: 200
        Content-Type: application/json;charset=utf-8
        Vary: Accept-Encoding
        
        {"id":5,"author":"meddle","body":"My new comment!","time":1368538076}

        We can see that the id of the new comment is 5.

      2. Now its time to read the new comment using its id – its URL will be http://forum-meddlings.rhcloud.com/comment/5
        Request:
        curl -i \
          -H "Accept: application/json" \
          http://forum-meddlings.rhcloud.com/comment/5
        
        Response:
        HTTP/1.1 200 
        Date: Tue, 14 May 2013 13:30:43 GMT
        Server: Apache/2.2.15 (Red Hat)
        X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
        Content-Length: 69
        Status: 200
        Content-Type: application/json;charset=utf-8
        Vary: Accept-Encoding
        
        {"id":5,"author":"meddle","body":"My new comment!","time":1368538076}

        So we’ve created a new comment and we know its location, it is persisted there.

      3. Let’s edit our new comment:
        Request:
        curl -i \
          -H "Accept: application/json" \
          -H "Content-Type: application/json" \
          -d '{"author": "meddle", "body": "My new comment! Edited!"}' \
          -X PUT \
          http://forum-meddlings.rhcloud.com/comment/5
        Response:
        HTTP/1.1 200 
        Date: Tue, 14 May 2013 13:37:10 GMT
        Server: Apache/2.2.15 (Red Hat)
        X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
        Content-Length: 77
        Status: 200
        Content-Type: application/json;charset=utf-8
        Vary: Accept-Encoding
        
        {"id":5,"author":"meddle","body":"My new comment! Edited!","time":1368538630}
      4. Now after updating our comment why don’t we see the whole list:
        Request:
         curl -i \
          -H "Accept: application/json" \
          http://forum-meddlings.rhcloud.com/comments
        Response:
        HTTP/1.1 200
        Date: Tue, 14 May 2013 13:44:00 GMT
        Server: Apache/2.2.15 (Red Hat)
        X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
        Content-Length: 288
        Status: 200
        Content-Type: application/json;charset=utf-8
        Vary: Accept-Encoding
        
        [{"id":1,"author":"meddle","body":"First","time":1368526814},
        {"id":2,"author":"meddle","body":"This is from the JSON API!","time":1368526899},
        {"id":3,"author":"Some Gangsta","body":"Yo man!","time":1368530204},{"id":5,"author":"meddle","body":"My new comment! Edited!","time":1368538630}]
      5. Now we can delete our comment:
        Request:
        curl -i \
          -H "Accept: application/json" \
          -X DELETE 
          http://forum-meddlings.rhcloud.com/comment/5
        
        Response:
        HTTP/1.1 204 
        Date: Tue, 14 May 2013 13:48:22 GMT
        Server: Apache/2.2.15 (Red Hat)
        X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
        Status: 204
        Content-Length: 0
        Content-Type: text/plain
      6. So if try to read the deleted comment, we will receive HTTP 404 – Not Found:
        Request:
         curl -i \
          -H "Accept: application/json" \
          http://forum-meddlings.rhcloud.com/comment/5
        
        Response:
         HTTP/1.1 404
         Date: Tue, 14 May 2013 13:49:49 GMT
         Server: Apache/2.2.15 (Red Hat)
         X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.17
         Content-Length: 30
         Status: 404
         Content-Type: application/json;charset=utf-8
        
        {"error":"Comment not found."}

This was one long post… But there is more : in the second part we will see the server implementation in Sinatra. Bye for now.