REST
REST stands for Representative State Transfer. It is an architectural style for communicating between two entities. Restful architecture is resource oriented. The services expose a set of resources to the client and the client can perform a set of operations on the resources which modify the state of the resource. It is a stateless protocol.
Why is REST important in the Cloud?
REST is one of the most common, standard and the simplest way of communicating between two entities or resources. REST is supported by every major programming language, used on both client side and server side. REST is used/supported by mobile applications, browsers, and backend systems. Many modern databases also provide a REST wrapper around their data APIs. Most of the Web 2.0 revolution happened around REST. So naturally, REST finds an important place in the Cloud design and architecture.
RESTful Design
Restful service design requires a paradigm shift in the way we think about designing services. In the SOAP world, it was all about operations. So we used to think, what will this web service "DO". But that is something which we should not do while designing Rest services. Let's take for example an order entry application. In the SOAP world, we would think about services like createOrder, updateOrder, addLineItems etc. To design the same services in Restful world, we need to identify all the resources in the application which needs to be exposed. These resources need not necessarily have a one to one mapping to the underlying schema. It is just the resources which matter to the client.
In our example, the resources could be Order, LineItem, Customer etc. We also need to establish a hierarchy amongst these resources for e.g., Customer -> Order -> LineItem.
How to identify the resources in REST?
In REST, the resources are identified by using URI. The URI should be something like a directory structure listing so that the client will not have too much of a trouble to guess the URI. The URI could also embed identifiers to pin point to a particular resource. For e.g., the url can embed an order ID, a customer ID etc.
In our example, the URI to identify an order with an order ID of 1000 for a customer Paul, could be something like: /customers/customer/paul/orders/order/1000/ Note that we could easily guess the hierarchy and drill down to the particular order. Removing /order/1000 will return an URI: /customers/customer/paul/orders/
The above URI will identify all the orders ordered by paul.
How to operate on Resources?
In order for the client to operate on the resources, Rest relies on HTTP protocol and uses the standard GET, PUT, POST, DELETE operations. The following table explains each of these operations.
HTTP Method | Description | Example |
---|---|---|
GET | Retrieve a resource | Retrieves the order with order ID 1000 |
PUT | Create/update a resource (completely replace existing resource). Used when we know the URI which will be created/updated | Update an order with ID 1000. The order details could be in Request body. |
POST | Create a resource when we do not know the URI which will be created | Create an order with details. The order details could be in Request body. |
DELETE | Delete a resource. | Delete an order with ID 1000. |
HEAD | Identical to GET except that the server MUST NOT return a message-body in the response. HEAD should be used to return meta data about the resource returned by GET. Clients can cache the results of HEAD. | HEAD could be used to check if a resource exists or to check the last modified date. |
PATCH | Updates a resource partially. This is generally used when we want to update only a few attributes of a resources and not the entire resource. The client can send only those attributes of the resource which needs to be updated. | Update order, with ID 1000 to update Status to Pending. |
PUT vs POST:
There is an argument over usage of PUT vs POST as to when we should use PUT and when we should use POST. PUT requires the operation to be idempotent, while POST does not. i.e., multiple invokes to PUT the same resource should result in the same outcome.
Let us take a closer look at this: The URI in consideration is: /customers/customer/paul/orders/order/1000
A PUT request to the above URI, should create a new order with an ID of 1000. If an order already exists with ID of 1000, the resource should get replaced with the data provided in this request. So, no matter how many times we invoke PUT for ID of 1000, the outcome will always be an order with ID 1000. That is idempotency. The definition of POST says that, POST should be used to create a child resource as well as the URI. i.e., the client is not aware of the URI being generated.
1. Use case for POST:
A typical use case for POST is, when a client intends to "Create an order and get back an ID which could be used in further requests". So, a POST request to '/customers/customer/paul/orders/order' will generate an Order with ID (say) 1000 and it will also create an URI '/customers/customer/paul/orders/order/1000'.
Subsequent PUT requests to the above URI will update the order with ID 1000. So, POST could be used to create orders when the server will generate unique IDs rather than client specifying the IDs.
2. Use case for PUT:
A typical use case for PUT is, when a client intends to "Create an order with ID 1000 which could be used for further requests". Note that here, 1000 need not be the primary key on the server side. That detail is hidden from the client. The server might generate its own primary Id and correlate it to 1000. All that the client cares is that, it should be able to get/update using that ID.
How to handle errors?
Exception scenarios could be handled by returning HTTP error codes like 400,404, 403 etc. These are standard HTTP codes and the standard should be followed depending on the scenario. For example, a HTTP code of 404 means that the URI doesn't exist.
What are the Response formats?
RESTful services can return XML, JSON etc. which is driven by the HTTP accept header. The service needs to explicitly set HTTP header indicating the response MIME type which it is returning. The client would then need to set the HTTP accept header accordingly. For example, a HTTP accept header of 'application/json' indicates that the client is ready to accept JSON response.
HATEOAS
An interesting point to note is that, in REST, we can also return URIs in the response. Let's say after a POST request to create a new order, instead of returning an ID, we can return the new URI, which could be used by the client for further GET/PUT requests. This can be done by returning the URI in the location header. For e.g., the service can return a header “Location: /order/1000”. This means, the client can issue GET requests at /order/1000 to retrieve the newly created order. This concept is known as Hypermedia as the engine of application state (HATEOAS).
How to describe the service API?
Similar to WSDL (Web Services Description Language), in the Rest world, we can describe the service API using WADL (Web Application Description Language). It is an xml based representation of the service API.