Eli Perelman

A jQuery User's Guide to REST

Being a JavaScript developer often means that you are left out of any discussions related to server-side code or architecture. Eventually this could present a usability or maintainability problem, and I’d like to bring up why you should care in regards to the topic of REST.

REST, or Representational State Transfer, can be thought of as a standard way for two parties to communicate about the actions to take on a resource or set of resources. To understand REST, let’s try to break this down into an analogy.

Resources

Yes, that’s right. Cheese. Cheese, for all intensive purposes, will be our resource. Think of a resource as a noun, an item. Something you can interact with, but not the action itself. Going back to grammar lessons, a noun can be a person, place, thing, or idea. That same principal applies to resources as well.

Verbs

Now, what can you do with cheese? You can make cheese, cut it (pun intended), store it, and yes, even eat it. These are all actions you can take on cheese. HTTP defines a standard set of actions that can be performed against all resources, called verbs, and today I am only going to focus on the four most supported ones: GET, POST, PUT, and DELETE.

URLs

In order to communicate with the server for your cheese interaction, you need to understand how to combine resources and verbs to form a request.

Pluarlity

The generally accepted way to identify a resource action in a URL is to use its plural form. For cheese it would be cheeses, user would be users, radius would be radii, and so on. Keep plurality in mind when forming your URL.

Forming the request

When browsing the internet, each request from page to page is a GET request. This same concept applies to accessing pages RESTfully. For example, if we want to go to a page that contains a list of all our cheeses, the URL would look like this:

Notice there is no action stating we want to get a list like http://localhost/cheeses/getall or something similar. The action is provided by HTTP, so we don’t need to pollute our URL with it. This is what REST is all about.

Making any request, I get back a representation of the resource based on what resource I am requesting and the action I am performing on it. Since I am using my browser, I am using the GET verb to request the cheeses resources. Using that syntax, I should expect that the representation_ would be a list of cheeses, maybe in a table.

Now, let’s access a single piece of cheese:

Notice I am still working with my resource of cheeses, but this time I am providing the name or id of the cheese resource. Using the browser’s address bar will execute this as a GET request, so I will receive a page representation of a single cheese resource, possibly a form for editing this piece of cheese.

jQuery, AJAX, and other verbs

In the earlier days of web development before AJAX (yes, it’s true, it did exist at one point), there was not much of a concept of posting a form asynchronously, e.g. submitting a form would take you to another page. This was accomplished through a combination of a form tag’s action and method attributes. This can still be done in a RESTful manner.

1
2
3
4
5
6
7
<p>

    <form action="/cheeses/13579" method="POST">
        <input type="text" name="age" id="age" value="15 years" />
    </form>

</p>

This will cause all of the data included in the form to be placed in the request body, and submitted to the specified URL. A POST request tells the server that we are either adding to or changing information about a certain resource; we are changing something about our cheese.

This works the same way for AJAX requests as well (I am using jQuery since it is the most ubiquitous):

1
2
3
4
5
$.ajax({
    type: 'post',
    url: '/cheeses/13579',
    data: { age: '15 years' }
});

Matching URLs to resources and actions

In order to effectively form URL in the most standard and maintainable way, it’s going to help to know which URL scheme to use, and where:

Request from the server a list view or many resources for display:

GET http://localhost/cheeses

Request from the server a single resource for display

GET http://localhost/cheeses/13579

Request the server to create a resource:

POST http://localhost/cheeses/13579

Request the server to delete a particular resource:

DELETE http://localhost/cheeses/13579

1
2
3
4
$.ajax({
    type: 'delete',
    url: '/cheeses/13579'
});

Request the server to update particular resource:

PUT http://localhost/cheeses/13579

1
2
3
4
5
$.ajax({
    type: 'put',
    url: '/cheeses/13579',
    data: { name: 'Cheddar', age: '1 day' }
});

Response Codes

Notice above that I specifically said “Request the server” to do something. It is important to know that while you may request something, the server does not have to comply and may decide not to perform your request. Your application must handle this gracefully by reacting to HTTP response codes.

You know them, but maybe you didn’t pay much attention. Every time you visit a page that’s not found, you may see a cute message about it, but the browser was returned a 404 error. That is HTTP’s way of saying that what you requested wasn’t found. If you do happen to land on the page you requested successfully, chances are your browser was sent a 200 response.

When working with jQuery, these codes are abstracted away from you with the success and error handlers:

1
2
3
4
5
6
7
8
9
10
11
12
13
var request = $.ajax({
    type: 'post',
    url: '/cheeses/13579',
    data: { age: '15 years' }
});

request.success(function(data, textStatus, jqXHR) {
    // take action if successful
});

request.error(function(jqXHR, textStatus, errorThrown) {
    // take action if failed
});

The success methods are generally executed if the HTTP response was successful, for example if there was a 200, 302, or 304 response. The error function would be called in other instances such as 400 or 500 range responses.

Your ability to handle these responses in a RESTful application are very important. Fortunately jQuery provides an easy way to take different courses of action for different status codes (if necessary):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var handle200 = function(data, textStatus, jqXHR) {
    // take action if successful
};

var handle404 = function(jqXHR, textStatus, errorThrown) {
    // take action if failed
});

var request = $.ajax({
    type: 'post',
    url: '/cheeses/13579',
    data: { age: '15 years' },
    statusCode: {
        200: handle200,
        404: handle404
    }
});

With the statusCode object we can take different courses of action based on certain HTTP response codes. Any function can be assigned to a status code, and the arguments provided to it are based on the same criteria used to call one of the success or error methods we would have called before.

Some types of requests may return successful if the request was received successfully but the specific action may not have been immediately performed or is queued up for later execution as is often the case for DELETE requests. You may tell the server to delete a resource, and it may respond saying it was successful, only for you to find out later that nothing was actually deleted.

Understanding this is key: requesting the server to do something is not a guarantee that you will get what you ask for. That’s why it’s called a request. You cannot force the server to do something, and you should assume that it may not. The resiliency of your application will be determined on how you handle the cases where the server does not do as you ask. What may be even more difficult is handling the cases where the server may return something other than what you asked for. Having HTTP response codes will help your application handle each of these cases if you ever run across them or need that level of granularity.

Overview

Using REST in your code will ultimately improve the maintainability of your application, as having a simple, readable, and standard way to access and manipulate resources will assure routes stay decoupled and consistent. Remember to keep URLs descriptive of a resource, and let your verbs determine the action to take.

Comments