More than a decade after its introduction, REST has become one of the most important technologies for Web applications. Its importance is likely to continue growing quickly as all technologies move towards an API orientation. Every major development language now includes frameworks for building RESTful Web services. As such, it is important for Web developers and architects to have a clear understanding of REST and RESTful services. This tutorial explains REST architecturally, then dives into the details of using it for common API-based tasks.
While REST stands for Representational State Transfer, which is an architectural style for networked hypermedia applications, it is primarily used to build Web services that are lightweight, maintainable, and scalable. A service based on REST is called a RESTful service. REST is not dependent on any protocol, but almost every RESTful service uses HTTP as its underlying protocol. In this article, I examine the creation of RESTful services with HTTP.
Features of a RESTful Services
Every system uses resources. These resources can be pictures, video files, Web pages, business information, or anything that can be represented in a computer-based system. The purpose of a service is to provide a window to its clients so that they can access these resources. Service architects and developers want this service to be easy to implement, maintainable, extensible, and scalable. A RESTful design promises that and more. In general, RESTful services should have following properties and features, which I'll describe in detail:
- Representations
- Messages
- URIs
- Uniform interface
- Stateless
- Links between resources
- Caching
Representations
The focus of a RESTful service is on resources and how to provide access to these resources. A resource can easily be thought of as an object as in OOP. A resource can consist of other resources. While designing a system, the first thing to do is identify the resources and determine how they are related to each other. This is similar to the first step of designing a database: Identify entities and relations.
Once we have identified our resources, the next thing we need is to find a way to represent these resources in our system. You can use any format for representing the resources, as REST does not put a restriction on the format of a representation.
For example, depending on your requirement, you can decide to use JSON or XML. If you are building Web services that will be used by Web pages for AJAX calls, then JSON is a good choice. XML can be used to represent more complex resources. For example a resource called "Person" can be represented as:
Listing One: JSON representation of a resource.
1
2
3
4
5
6
|
Listing Two: XML representation of a resource.
1
2
3
4
5
6
7
8
9
10
|
<
Person
>
<
ID
>1</
ID
>
<
Name
>M Vaqqas</
Name
>
<
Country
>India</
Country
>
</
Person
>
|
In fact, you can use more than one format and decide which one to use for a response depending on the type of client or some request parameters. Whichever format you use, a good representation should have some obvious qualities:
- Both client and server should be able to comprehend this format of representation.
- A representation should be able to completely represent a resource. If there is a need to partially represent a resource, then you should think about breaking this resource into child resources. Dividing big resources into smaller ones also allows you to transfer a smaller representation. Smaller representations mean less time required to create and transfer them, which means faster services.
- The representation should be capable of linking resources to each other. This can be done by placing the URI or unique ID of the related resource in a representation (more on this in the coming sections).
Messages
The client and service talk to each other via messages. Clients send a request to the server, and the server replies with a response. Apart from the actual data, these messages also contain some metadata about the message. It is important to have some background about the HTTP 1.1 request and response formats for designing RESTful Web services.
HTTP Request
An HTTP request has the format shown in Figure 1:
Figure 1: HTTP request format.
<VERB>
is one of the HTTP methods like GET
, PUT
, POST
, DELETE
, OPTIONS
, etc
<URI>
is the URI of the resource on which the operation is going to be performed
<HTTP Version>
is the version of HTTP, generally "HTTP v1.1"
.
<Request Header>
contains the metadata as a collection of key-value pairs of headers and their values. These settings contain information about the message and its sender like client type, the formats client supports, format type of the message body, cache settings for the response, and a lot more information.
<Request Body>
is the actual message content. In a RESTful service, that's where the representations of resources sit in a message.
There are no tags or markups to denote the beginning or end of a section in an HTML message.
Listing Three is a sample POST
request message, which is supposed to insert a new resourcePerson
.
Listing Three: A sample POST request.
1
2
3
4
5
6
7
8
9
10
11
|
Host: MyService
Content-Type: text/xml; charset=utf-8
Content-Length: 123
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
Person
>
<
ID
>1</
ID
>
<
Name
>M Vaqqas</
Name
>
<
Country
>India</
Country
>
</
Person
>
|
You can see the POST
command, which is followed by the URI and the HTTP version. This request also contains some request headers. Host
is the address of the server. Content-Type
tells about the type of contents in the message body. Content-Length
is the length of the data in message body. Content-Length
can be used to verify that the entire message body has been received. Notice there are no start or end tags in this message.
Listing Four is an actual GET
request that was created by my browser when I tried to visit the HTTP 1.1 specifications on w3.org:
Listing Four: A GET request.
1
2
3
4
5
6
|
GET http://www.w3.org/Protocols/rfc2616/rfc2616.html HTTP/1.1
Host: www.w3.org
Accept: text/html,application/xhtml+xml,application/xml; …
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 …
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,hi;q=0.6
|
There is no message body in this request. The Accept
header tells the server about the various presentation formats this client supports. A server, if it supports more than one representation format, it can decide the representation format for a response at runtime depending on the value of the Accept
header. User-Agent
contains information about the type of client who made this request. Accept-Encoding/Language
tells about the encoding and language this client supports.
HTTP Response
Figure 2 shows the format of an HTTP response:
Figure 2: HTTP response format.
The server returns <response code>
, which contains the status of the request. This response code is generally the 3-digit HTTP status code.
<Response Header>
contains the metadata and settings about the response message.
<Response Body>
contains the representation if the request was successful.
Listing Five is the actual response I received for the request cited in Listing Three:
Listing 5: An actual response to a GET request..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
HTTP/1.1 200 OK
Date: Sat, 23 Aug 2014 18:31:04 GMT
Server: Apache/2
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
Accept-Ranges: bytes
Content-Length: 32859
Cache-Control: max-age=21600, must-revalidate
Expires: Sun, 24 Aug 2014 00:31:04 GMT
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<
head
><
title
>Hypertext Transfer Protocol -- HTTP/1.1</
title
></
head
>
<
body
>
...
|
The response code 200 OK
means that everything went well and the response message body contains a valid representation of the resource I requested. In this case, the representation is an HTML document that is declared by Content-Type
header in the response header. The headers in the message are self explanatory, but I will discuss some of them later in this article. There are many other attributes. You can catch and inspect such HTTP requests and responses using a free tool called Fiddler.
Addressing Resources
REST requires each resource to have at least one URI. A RESTful service uses a directory hierarchy like human readable URIs to address its resources. The job of a URI is to identify a resource or a collection of resources. The actual operation is determined by an HTTP verb. The URI should not say anything about the operation or action. This enables us to call the same URI with different HTTP verbs to perform different operations.
Suppose we have a database of persons and we wish to expose it to the outer world through a service. A resource person
can be addressed like this:
http://MyService/Persons/1
This URL has following format: Protocol://ServiceName/ResourceType/ResourceID
Here are some important recommendations for well-structured URIs:
- Use plural nouns for naming your resources.
- Avoid using spaces as they create confusion. Use an
_
(underscore) or–
(hyphen) instead. - A URI is case insensitive. I use camel case in my URIs for better clarity. You can use all lower-case URIs.
- You can have your own conventions, but stay consistent throughout the service. Make sure your clients are aware of this convention. It becomes easier for your clients to construct the URIs programmatically if they are aware of the resource hierarchy and the URI convention you follow.
- A cool URI never changes; so give some thought before deciding on the URIs for your service. If you need to change the location of a resource, do not discard the old URI. If a request comes for the old URI, use status code
300
and redirect the client to the new location. - Avoid verbs for your resource names until your resource is actually an operation or a process. Verbs are more suitable for the names of operations. For example, a RESTful service should not have the URIs
http://MyService/FetcthPerson/1
orhttp://MyService/DeletePerson?id=1
.
Query Parameters in URI
The preceding URI is constructed with the help of a query parameter:
http://MyService/Persons?id=1
The query parameter approach works just fine and REST does not stop you from using query parameters. However, this approach has a few disadvantages.
- Increased complexity and reduced readability, which will increase if you have more parameters
- Search-engine crawlers and indexers like Google ignore URIs with query parameters. If you are developing for the Web, this would be a great disadvantage as a portion of your Web service will be hidden from the search engines.
The basic purpose of query parameters is to provide parameters to an operation that needs the data items. For example, if you want the format of the presentation to be decided by the client. You can achieve that through a parameter like this:
http://MyService/Persons/1?format=xml&encoding=UTF8
or
http://MyService/Persons/1?format=json&encoding=UTF8
Including the parameters format
and encoding
here in the main URI in a parent-child hierarchy will not be logically correct as they have no such relation:
http://MyService/Persons/1/json/UTF8
Query parameters also allow optional parameters. This is not otherwise possible in a URI. You should use query parameters only for the use they are intended for: providing parameter values to a process.