The core architectural elements of a RESTful system
Having learned the basics of a RESTful system, you are now ready to meet the more exciting concepts of REST. In this section, we will learn the core architectural elements that make a system RESTful.
A uniform interface is fundamental to the architecture of any RESTful system. In plain words, this term refers to a generic interface to manage all interactions between a client and a server in a unified way. All resources (or business data) involved in the client-server interactions are dealt with by a fixed set of operations. The following are core elements that form a uniform interface for a RESTful system:
- Resources and their identifiers
- Representations of resources
- Generic interaction semantics for the REST resources
- Self-descriptive messages
- Hypermedia as the engine of an application state
Let's look at these items in detail.
Resources
A RESTful resource is anything that is addressable over the Web. By addressable, we mean resources that can be accessed and transferred between clients and servers. Subsequently, a resource is a logical, temporal mapping to a concept in the problem domain for which we are implementing a solution.
Here are some examples of the REST resources:
- A news story
- The temperature in NY at 4:00 p.m. EST
- A tax return stored in the IRS database
- A list of code revision history in a repository such as SVN or CVS
- A student in a classroom in a school
- A search result for a particular item in a Web index, such as Google
Even though a resource's mapping is unique, different requests for a resource can return the same underlying binary representation stored in the server. For example, let's say we have a resource within the context of a publishing system. Then, a request for the latest revision published
and a request for revision number 12
will at some point in time return the same representation of the resource. In this example, the last revision is Version 12. However, when the latest revision published is increased to Version 13, a request to the latest revision will return Version 13, and a request for revision 12 will continue returning Version 12. This implies that in a RESTful architecture, each resource can be accessed directly and independently, and sometimes, different requests may point to the same resource.
As we are using HTTP to communicate, we can transfer a variety of data types between clients and servers as long as the data type used is supported by HTTP. For example, if we request a text file from CNN, our browser receives a text file. If we request a Flash movie from YouTube, our browser receives a Flash movie. The data is streamed in both cases over TCP/IP and the browser knows how to interpret the binary streams because of the Content-Type
header present in the HTTP response header. Following this principle, in a RESTful system, the representation of a resource in the response body depends on the desired Internet media type, which is specified within the request header sent by the client.
URI
A URI is a string of characters used to identify a resource over the Web. In simple words, the URI in a RESTful web service is a hyperlink to a resource, and it is the only means for clients and servers to exchange representations.
The client uses a URI to locate the resources over Web and then, sends a request to the server and reads the response. In a RESTful system, the URI is not meant to change over time as it may break the contract between a client and a server. More importantly, even if the underlying infrastructure or hardware changes (for example, swapping the database servers) for a server hosting REST APIs, the URIs for resources are expected to remain the same as long as the web service is up and running.
The representation of resources
The representation of resources is what is sent back and forth between clients and servers in a RESTful system. A representation is a temporal state of the actual data located in some storage device at the time of a request. In general terms, it is a binary stream together with its metadata that describes how the stream is to be consumed by the client. The metadata can also contain extra information about the resource, for example, validation, encryption information, or extra code to be executed at runtime.
Throughout the life of a web service, there may be a variety of clients requesting resources. Different clients can consume different representations of the same resource. Therefore, a representation can take various forms, such as an image, a text file, an XML, or a JSON format. However, all clients will use the same URI with appropriate Accept
header values for accessing the same resource in different representations.
For the human-generated requests through a web browser, a representation is typically in the form of an HTML page. For automated requests from the other web services, readability is not as important and a more efficient representation, such as JSON or XML, can be used.
Generic interaction semantics for REST resources
In the previous sections, we introduced the concepts of resources and representations. We learned that resources are mappings of the actual entity states that are exchanged between clients and servers. Further, we discussed that representations are negotiated between clients and servers through the communication protocol (HTTP) at runtime. In this section, we will learn about the generics of interaction semantics and self-descriptive messages followed for the client-server communication in a RESTful system.
Developing RESTful web services is similar to what we have been doing up to this point with our web applications. In a RESTful web service, resources are exchanged between the client and the server, which represent the business entities or data. HTTP specifies methods or actions for the resources. The most commonly used HTTP methods or actions are POST
, GET
, PUT
, and DELETE
. This clearly simplifies the REST API design and makes it more readable. On the other hand, in traditional application development, we can have countless actions with no naming or implementation standards. This may call for more development effort for both the client and the server, and make the APIs less readable.
In a RESTful system, we can easily map our CRUD actions on the resources to the appropriate HTTP methods such as POST
, GET
, PUT
, and DELETE
. This is shown in the following table:
Data action |
HTTP equivalent |
---|---|
|
|
|
|
|
|
|
|
In fact, the preceding list of HTTP methods is incomplete. There are some more HTTP methods available, but they are less frequently used in the context of RESTful implementations. Of these less frequent methods, OPTIONS
and HEAD
are used more often than others. So, let's glance at these two method types:
OPTIONS
: This method is used by the client to determine the options or actions associated with the target resource, without causing any action on the resource or retrieval of the resourceHEAD
: This method can be used for retrieving information about the entity without having the entity itself in the response
In their simplest form, RESTful web services are networked applications that manipulate the state of resources. In this context, resource manipulation means resource creation, retrieval, update, and deletion. However, RESTful web services are not limited to just these four basic data manipulation concepts. They can even be used for executing business logic on the server, but remember that every result must be a resource representation of the domain at hand.
A uniform interface brings all the aforementioned abstractions into focus. Consequently, putting together all these concepts, we can describe RESTful development with one short sentence: we use URIs to connect clients and servers in order to exchange resources in the form of representations.
Let's now look at the four HTTP request types in detail and see how each of them is used to exchange representations to modify the state of resources.
The HTTP GET method
The method, GET
, is used to retrieve resources. Before digging into the actual mechanics of the HTTP GET
request, we first need to determine what a resource is in the context of our web service and what type of representation we are exchanging.
For the rest of this section, we will use the example of a RESTful web service handling department details for an organization. For this service, the JSON representation of a department looks like the following:
{"departmentId":10,"departmentName":"IT","manager":"John Chen"}
The JSON representation of the list of departments looks like the following:
[{"departmentId":10,"departmentName":"IT","manager":"John Chen"}, {"departmentId":20,"departmentName":"Marketing","manager":"Ameya J"}, {"departmentId":30,"departmentName":"HR","manager":"Pat Fay"}]
With our representations defined, we now assume URIs of the form http://www.packtpub.com/resources/departments
to access a list of departments, and http://www.packtpub.com/resources/departments/{name}
to access a specific department with a name (unique identifier).
Tip
To keep this example simple and easy to follow, we treat the department name as a unique identifier here. Note that in real life, you can use a server-generated identifier value, which does not repeat across entities, to uniquely identify a resource instance.
We can now begin making requests to our web service. For instance, if we wanted a record for the IT department, we would make a request to the following URI: http://www.packtpub.com/resources/departments/IT
.
A representation of the IT department at the time of the request may look like the following code:
{"departmentId":10,"departmentName":"IT","manager":"John Chen"}
Let's have a look at the request details. A request to retrieve details of the IT department uses the GET
method with the following URI:
http://www.packtpub.com/resources/departments/IT
Let's see what happens when a client requests for the IT department by using the preceding mentioned URI. Here is the sequence diagram for the GET
request:
What is happening here?
- A Java client makes an HTTP request with the
GET
method type andIT
as the identifier for the department. - The client sets the representation type that it can handle through the
Accept
request header field. This request message is self-descriptive:- It uses a standard method (the
GET
method in this example) with known semantics for retrieving the content - The content type is set to a well-known media type (text/plain)
- This request also declares the acceptable response format
- It uses a standard method (the
- The web server receives and interprets the
GET
request to be a retrieve action. At this point, the web server passes control to the underlying RESTful framework to handle the request. Note that RESTful frameworks do not automatically retrieve resources, as that is not their job. The job of a framework is to ease the implementation of the REST constraints. Business logic and storage implementation is the role of the domain-specific Java code. - The server-side program looks for the IT resource. Finding the resource could mean looking for it in some data store such as a database, a file system, or even a call to a different web service.
- Once the program finds the IT department details, it converts the binary data of the resource to the client's requested representation. In this example, we use the JSON representation for the resource.
- With the representation converted to JSON, the server sends back an HTTP response with a numeric code of
200
together with the JSON representation as the payload. Note that if there are any errors, the HTTP server reports back the proper numeric code, but it is up to the client to correctly deal with the failure. Similar to the request message, the response is also self-descriptive.
All the messages between a client and a server are standard HTTP calls. For every retrieve action, we send a GET
request and we get an HTTP response back with the payload of the response being the representation of the resource or, if there is a failure, a corresponding HTTP error code (for example, 404
, if a resource is not found; 500
, if there is a problem with the Java code in the form of an exception).
Getting a representation for all departments works the same way as getting a representation for a single department, although we now use the URI as http://www.packtpub.com/resources/departments
and the result is the JSON representation, which looks like the following code:
[{"departmentId":10,"departmentName":"IT","manager":"John Chen"}, {"departmentId":20,"departmentName":"Marketing","manager":"Ameya J"}, {"departmentId":30,"departmentName":"HR","manager":"Pat Fay"}]
Note
The HTTP GET
method should only be used to retrieve representations, not for performing any update on the resource. A GET
request must be safe and idempotent. For more information, refer to http://www.w3.org/DesignIssues/Axioms.
For a request to be safe, it means that multiple requests to the same resource do not change the state of the data in the server. Assume that we have a representation, R
, and requests happen at a time, t
. Then, a request at time t1
for resource R
returns R1
; subsequently, a request at time t2
for resource R
returns R2
provided that no further update actions have been taken between t1
and t2
. Then, R1 = R2 = R
.
For a request to be idempotent, multiple calls to the same action should not change the state of the resource. For example, multiple calls to create resource R
at times t1
, t2
, and t3
mean that R
will exist only as R
and the calls at times t2
and t3
are ignored.
The HTTP POST method
The POST
method is used to create resources. As we are creating a department, we use the HTTP POST
method. Again, the URI to create a new department in our example is http://www.packtpub.com/resources/departments
. The method type for the request is set by the client.
Assume that the Sales
department does not exist in our list, and we want to add it to the list. The Sales
data representation looks like the following:
{"departmentName":"Sales","manager":"Tony Greig"}
Now, the sequence diagram of our POST
request looks like the following:
The series of steps for the POST
request is as follows:
- A Java client makes a request to the
http://www.packtpub.com/resources/departments
URI with the HTTP method set toPOST
. - The
POST
request carries the payload along with it in the form of a JSON representation of theSales
department. - The server receives the request and lets the
REST
framework handle it; our code within the framework executes the proper commands to store the representation, irrespective of which data persistence mechanism is used. - Once the new resource is stored, a response code,
2xx
(representing a successful operation), is sent back. In this example, the server sends201 Created
, which implies that the server has fulfilled the request by creating a new resource. The newly created resource is accessible by traversing the URI given by aLocation
header field. If it is a failure, the server sends the appropriate error code.
The HTTP PUT method
The PUT
method is used to update resources. To update a resource, we first need its representation in the client; secondly, at the client level, we update the resource with the new value(s) that we want; and finally, we update the resource by using a PUT
request together with the representation as its payload.
In this example, let's add a manger to the Sales
department that we created in the previous example.
Our original representation of the Sales
department is as follows:
{"departmentId":40,"departmentName":"Sales","manager":"Tony Greig" }
Let's update the manager for the Sales
department; our representation is as follows:
{"departmentId":40,"departmentName":"Sales","manager":"Ki Gee"}
We are now ready to connect to our web service to update the Sales
department by sending the PUT
request to http://www.packtpub.com/resources/departments/Sales
. The sequence diagram of our PUT
request is as follows:
The series of steps for the PUT
request is as follows:
- A Java client makes a
PUT
request tohttp://www.packtpub.com/resources/departments/Sales
with the JSON payload representing the modified department details. - The server receives the request and lets the REST framework handle it. At this point, we let our code execute the proper commands to update the representation of the
Sales
department. Once completed, a response is sent back. The204 No Content
response code indicates that the server has fulfilled the request but does not return the entity body.
The HTTP DELETE method
The DELETE
method is used to delete the resource. In this example, we will delete a resource by making use of the same URI that we used in the other three cases.
Assume that we want to delete the Sales
department from the data storage. We send a DELETE
request to our service with the following URI: http://www.packtpub.com/resources/departments/Sales
.
The sequence diagram for our DELETE
request is shown in the following diagram:
The series of steps for the DELETE
request is as follows:
- A Java client makes a
DELETE
request tohttp://www.packtpub.com/resources/departments/Sales
. - The server receives the request and lets the REST framework handle it. At this point, the server code executes the proper commands to delete the representation of the
Sales
department. - Once completed, a response is sent back.
With this, we have covered all the major actions that can be carried out on resources in a RESTful web service. To keep things simple during our discussion, we did not talk about the actual implementation of the CREATE
, READ
, UPDATE
, and DELETE
operations on the resource. In all three examples, we presumed that we have a well-behaved web service that adheres to the RESTful guidelines and the client and the server communicate over HTTP. We use the communication protocol to send action requests, and our resource representations are sent back and forth through unchanging URIs. We will cover more detailed end-to-end examples later in this book.
Note
A point to note about our sequence diagrams is that we are assuming that all the underlying technologies are Java technologies (servers and clients). However, these are just components in the whole architecture and the explanations apply to any technology stack.
Hypermedia as the Engine of Application State
Hypermedia as the Engine of Application State (HATEOAS) is an important principle of the REST application architecture. The principle is that the model of application changes from one state to another by traversing the hyperlinks present in the current set of resource representations (the model). Let's learn this principle in detail.
In a RESTful system, there is no fixed interface between the client and the server as you may see in a conventional client-server communication model such as Common Object Request Broker Architecture (CORBA) and Java Remote Method Invocation (Java RMI). With REST, the client just needs to know how to deal with the hypermedia links present in the response body; next, the call to retrieve the appropriate resource representation is made by using these dynamic media links. This concept makes the client-server interaction very dynamic and keeps it different from the other network application architectures.
Here is an example illustrating the HATEOAS principle. In this example, the http://www.packtpub.com/resources/departments/IT
URI returns the following response to the client:
{"departmentId":10, "departmentName":"IT", "manager":"John Chen, "links": [ { "rel": "employees", "href": "http://packtpub.com/resources/departments/IT/employees" } ]"}
This is the current state of the system. Now, to get the employees belonging to the department, the client traverses the hyperlink present in the response body, namely http://www.packtpub.com/resources/departments/IT/employees
. This URI returns the following employee list. The application state now changes into the following form (as represented by the response content):
[{"employeeId":100, "firstName":"Steven", "lastName":"King", "links": [ { "rel": "self", "href": "http://www.packtpub.com/resources/employees/100" }] }, {"employeeId":101, "firstName":"Neena", "lastName":"Kochhar", "links": [ { "rel": "self", "href": "http://www.packtpub.com/resources/employees/101" }] }]
In this example, the application state changes from one state to another when the client traverses the hypermedia link. Hence, we refer to this implementation principle as Hypermedia as the Engine of Application State.