January 14, 2011 6 Comments
REST is an architecture style for designing networked applications. It relies on a stateless, client-server, cacheable communications protocol — and in virtually all cases, the HTTP protocol is used.
REST web services architecture conforms to the W3C’s Web Architecture, and leverages the architectural principles of the Web, building its strength on the proven infrastructure of the Web. It utilizes the semantics of HTTP whenever possible and most of the principles, constraints, and best practices published by W3C’s Technical Architecture Group (TAG) also apply.
The REST web services architecture is related to the Service Oriented Architecture. This limits the interface to HTTP with the four well-defined verbs: GET, POST, PUT, and DELETE. REST web services also tend to use XML as the main messaging format.
Implementing REST correctly requires a resource-oriented view of the world instead of the object-oriented views many developers are familiar with. A resource is an abstract thing identified by a URI.
1. Addressable Resources: Every “thing” on your network should have an ID. With REST over HTTP, every object will have its own specific URI.
2. A Uniform, Constrained Interface: When applying REST over HTTP, stick to the methods provided by the protocol. This means following the meaning of GET, POST, PUT, and DELETE religiously.
3. Representation oriented: You interact with services using representations of that service. An object referenced by one URI can have different formats available. Different platforms need different formats. AJAX may need JSON. A Java application may need XML.
4. Communicate statelessly: Stateless applications are easier to scale.
REST development guidelines
The creator of a URI decides the encoding of the URI, and users should not derive metadata from the URI itself. URI opacity only applies to the path of a URI. The query string and fragment have special meaning that can be understood by users. There must be a shared vocabulary between a service and its consumers.
Query String Extensibility:
A service provider should ignore any query parameters it does not understand during processing. If it needs to consume other services, it should pass all ignored parameters along. This practice allows new functionality to be added without breaking existing services.
Deliver Correct Resource Representation:
A resource may have more than one representation. There are four frequently used ways of delivering the correct resource representation to consumers:
1. Server-driven negotiation: The service provider determines the right representation from prior knowledge of its clients or uses the information provided in HTTP headers like Accept, Accept-Charset, Accept-Encoding, Accept-Language, and User-Agent. The drawback of this approach is that the server may not have the best knowledge about what a client really wants.
2. Client-driven negotiation: A client initiates a request to a server. The server returns a list of available of representations. The client then selects the representation it wants and sends a second request to the server. The drawback is that a client needs to send two requests.
3. Proxy-driven negotiation: A client initiates a request to a server through a proxy. The proxy passes the request to the server and obtains a list of representations. The proxy selects one representation according to preferences set by the client and returns the representation back to the client.
4. URI-specified representation: A client specifies the representation it wants in the URI query string.
It is actually quite easy to implement an asynchronous REST service. An asynchronous service needs to perform the following:
1. Return a receipt immediately upon receiving a request.
2. Validate the request.
3. If the request if valid, the service must act on the request as soon as possible. It must report an error if the service cannot process the request after a period of time defined in the service contract.
Transaction Lifecycle and Status URI
The status resource can be seen as a different view of its associated transaction resource. The status URI should only differ in the query string with an additional status parameter. For example:
A transaction request submitted to a service will experience the following lifecycle as defined in Web Service Management: Service Life Cycle
As an example of the status XML, when a request is just received:
<status state=”received” timestamp=”2009-12-03T12:34:33+5:30″ />
The XML contains a state attribute, which indicates the current state of the request. Other possible values of the state attribute are processing, processed, and failed. When a request is processed:
<status state=”processed” timestamp=”2009-12-03T12:34:33+5:30″ >
<result uri=”http://example.com/rest/123/abc” />
Receiving and Sending XML
When receiving and sending XML, one should follow the principle of strict out and loose in. When sending XML, one must ensure it is validated against the relevant schema. When receiving an XML document, one should only validate the XML against the smallest set of schema that is really needed. Any software agent must not change XML it does not understand.
Exception handling and propagation
To deal with exceptions, JAX-RS provides the WebApplicationException, which extends the Java RuntimeException class. The WebApplicationException can take an HTTP status code or javax.ws.rs.core.Response object as part of the constructor. The Response object can be used to set the entity information providing a user readable error message along with the HTTP status code.
Typically, exception handling for RESTful service would fall into one of the following categories:
1. The implementation class can throw an unchecked WebApplicationException with the required HTTP Error code. The HTTP specification defines which HTTP response code should be used for unsuccessful requests, which can be interpreted by clients in a standard way. For example, Status code 4xx defines client error, such as Bad request, and 5xx defines the server request where server failed to fulfill a valid request.
2. The implementation class can create a javax.ws.rs.core.Response object and send a custom error message to the client or send the required HTTP status code in the response.
3. The implementation class can throw a checked exception and you can wire an ExceptionResolver implementation to convert the application exception to the Response object. The ExceptionResolver interface provides a contract for a provider that maps Java exception to a Response. For instance, if you are fetching information from the database, and a record does not exist, and your application throws a RecordNotFound exception, then you can map this exception to a Response object using your ExceptionResolver implementation. The Response object can be populated with a custom error message and sent back to the client, as mentioned in the second approach.