Introduction
The author
REST was introduced by Roy T. Fielding in chapter 5 of his dissertation written in 2000: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm. Not only was Roy involved in formulating REST, he is also a principal author of the HTTP protocol, co-founder of the Apache HTTP server project and Director of The Apache Software Foundation (among other things). HTTP 1.1 was designed with the concepts of REST in mind.
Roy Fielding
Image of Roy Fielding from http://roy.gbiv.com/
The definition
Representational state transfer (REST) is a software architectural style consisting of a coordinated set of architectural constraints applied to components, connectors, and data elements, within a distributed hypermedia system. REST ignores the details of component implementation and protocol syntax in order to focus on the roles of components, the constraints upon their interaction with other components, and their interpretation of significant data elements. Thus REST is not limited to HTTP as a transport protocol or JSON as a message exchange pattern. Roy has even worked on an alternative to the HTTP protocol; Waka.
Components
Components can be grouped in roles. Examples of component roles:
- user agents
- proxies
- clients
- origin servers
Connectors
Connectors are wrappers which provide an abstraction for accessing and transferring resource representations. Examples of connectors. Connectors are wrappers for transferring representations.
- libraries such as libwww
- the Java class HttpURLConnection
- bind (for DNS)
- SOCKS
Data elements are for example
- resources
- resource identifiers (e.g. URI's)
- control data
- representations
Constraints
The constraints applying to components, connectors and data elements in REST are (using my own description and interpretation):
- Separation of client-server concerns. The server should not be concerned with UI and the client is not concerned with storage.
- Services are stateless. This statement has implications for using sessions. The following explains it well; http://stackoverflow.com/questions/2641901/how-to-manage-state-in-rest. When you want to keep an object available between requests, the object should become a new resource which can be accessed. Another REST solution would be to send required information with each request.
- Clients need to be able to obtain information from services about if a result is cache-able. This can dramatically improve performance.
- For scalability purposes, the system can be layered. A client should not be able to tell whether it is connecting directly to a resource or if the resource is cached or proxied. This allows for example load-balancing.
- Services should provide a uniform interface. Information should be transferred in a standardized form. This also allows for more easy re-use of services and often interoperability by default.
- To avoid tight coupling between client and server, if a resource requires specialized processing of which the client should not be aware, the server should provide the client with the code to allow processing of the resource. This constraint is optional.
Maturity
Steps toward REST (http://martinfowler.com/articles/richardsonMaturityModel.html)
- Level 0: POX. Plain old XML send by using HTTP POST or GET requests
- Level 1: Resources are identified by URI's
- Level 2: HTTP verbs are used to do CRUD operations.
- Level 3: HATEOAS (Hypertext As The Engine Of Application State). The response contains information the client can use in a next request. For example relative links to created resources are returned.
From the REST dissertation: 'What distinguishes HTTP from RPC isn't the syntax. It isn't even the different characteristics gained from using a stream as a parameter, though that helps to explain why existing RPC mechanisms were not usable for the Web. What makes HTTP significantly different from RPC is that the requests are directed to resources using a generic interface with standard semantics that can be interpreted by intermediaries almost as well as by the machines that originate services. RPC mechanisms, in contrast, are defined in terms of language APIs, not network-based applications.'
REST is often confused with RPC. The hotel booking example below illustrates the difference nicely. In order to provide an implementation example, I have created a simple Java "REST" service (it does not follow all REST constraints to the letter since it is supposed to be a simple illustration) using JAX-RS.
Hotel booking
As you can see below, with a REST style service, the URI is used to identify the object hierarchy, type of object and determine which object specifically is used. The object does not need to be provided in the message since identification of the object is done by using the URI. This differs from RPC style in which a function is called with parameters and the URI holds little more meaning then the location of the function to be called. Often RPC style webservices also do not use the HTTP verbs like REST style services do.
Making a reservation
RPC: http://MyHotel:8080/Reservation/CreateReservation (HTTP POST: <reservation RoomNumber="123"><Breakfast>Yes</Breakfast><GoldMember>Yes</GoldMember><! --Rest of the booking request--></reservation>)
REST: http://MyHotel:8080/Reservations/Reservation?RoomNumber=123 (HTTP POST: <reservation><Breakfast>Yes</Breakfast><GoldMember>Yes</GoldMember><! --Rest of the booking request--></reservation>)
As can be seen in the above example, the URI used to send the request to RPC style, calls a method which resides at a specific URI. The URI does not identify a resource such as a reservation. This information is contained in the transported message. Also, the client has to know where to find this function and how it is called. When doing a REST style call, the URI can be seen as a tree at which resources reside. The correct room reservation is created by specifying the roomnumber in the URI. What is transported in the message is data used for the creation of the resource but not the identification of the resource itself. In order to determine how to traverse the resource tree, HTTP OPTIONS requests or WADL's can be used. These will be described in more detail later.
Retrieving a reservation
RPC: http://MyHotel:8080/Reservation/GetReservation?RoomNumber=123 (HTTP GET)
REST: http://MyHotel:8080/Reservations/Reservation?RoomNumber=123 (HTTP GET)
When retrieving a reservation RPC style, again a function is called. REST style, the same URI is used as when creating the resource, only the HTTP verb indicates the operation to be performed. This illustrates the uniform interface constraint of REST.
Cancelling a reservation
RPC: http://MyHotel:8080/Reservation/DeleteReservation (HTTP POST: <reservation RoomNumber="123"><! --Rest of the reservation--></reservation>)
REST: http://MyHotel:8080/Reservations/Reservation?RoomNumber=123 (HTTP DELETE)
For the cancellation of a reservation, again REST style, the HTTP verb determines the action to be taken on the resource. RPC style, you would need to know the method to call for the action is DeleteReservation. RPC style requires the client to know more about the implementation.
Example JAX-RS webservice
JAX-RS is a Java framework for building REST webservices. I created a simple helloworld JAX-RS service with the following code. Helloworld is more of a method then a 'resource'. In order to give a quick example without requiring a database and DAO's (http://en.wikipedia.org/wiki/Data_access_object).
package restwebservice;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/helloworld")
public class HelloWorld {
public HelloWorld() {
}
/**
* @param input
* @return
*/
@GET
@Path("{name}")
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
public Response getData(@PathParam("name") String input) {
return Response.ok("{\"Response\": \"Hello " + input + "\"}", MediaType.APPLICATION_JSON).build();
}
}
As can be seen from this example, I specify what should be done when the resource helloworld is called with a name. The name is supplied as part of the URI. I also supply what the service produces and consumes. This information is used to generate a WADL. A WADL is to a REST service what a WSDL is to a SOAP service. The WADL contains a set of resource elements. Each resource contains param elements to describe the inputs, and method elements which describe the request and response of a resource. The request element specifies how to represent the input, what types are required and any specific HTTP headers that are required. The response describes the representation of the service's response, as well as any fault information, to deal with errors.
The WADL after deployment in this example (on my local machine, application server running on port 7101) could be obtained by going to http://localhost:7101/restservice/resources/application.wadl. Notice that it is specified in the WADL how to call the service in order to obtain the WADL. A nice example of a self-describing service.
A recommended read on how to supply parameters to a REST service is the following: http://www.soapui.org/REST-Testing/understanding-rest-parameters.html. This also shows how SOAP UI can be configured to use the several methods. I am using a template style parameter in my example service.
I can do a HTTP GET request on an URL like http://localhost:7101/restservice/resources/helloworld/Maarten to call the service with name=Maarten.
Some tips when you are going to develop Java REST services;
- use the javax.ws.rs.core.Response class instead of returning a plain String. It makes it possible to supply additional properties to the response. You will need MIME type, HTTP response code, etc.
- use JAX-RS together with Jersey. You will get a lot of functionality for free such as WADL generation
- clients for REST services can easily be generated if a WADL is available.
- use Jackson to make working with JSON easier
- SOAP-UI can be used to test REST services. SOAP-UI can also generate WADL's for you (based on how you configure the request for a service) if the service you are using doesn't provide one.
Conclusion
When reading bits about REST, I found it to be a lot more then I originally thought it would be. I did not consider at first that REST would be a relatively abstract style, independent of transport and protocol. The constraints posed by REST, when implemented correctly, can increase client/server loose coupling and service interoperability, which are things every developer should strife to achieve in my opinion. Most Middleware developers will encounter RESTful services (or so-called RESTful services). It is good to understand what they are, what they should be and how they work (how you can and should work with them).
I've used SOAP a lot when developing webservices. REST has been mentioned as an alternative to SOAP. Even currently on Wikipedia. SOAP however is a protocol and REST is an architectural style thus it is like comparing apples to oranges. You can compare SOAP to JSON over HTTP however. JSON is less verbose (requires less characters to transport) then XML. JSON is often not strongly typed and it is harder to check if a message is correct because often there is no formal message definition for a JSON message. JSON is easy to do in Javascript. XML is harder. SOAP has several WS-* standards to provide additional functionality such as security, transactions and correlation. Thus in my opinion JSON over HTTP is more suitable if Javascript is used a lot, network bandwidth is a limitation and SOAP functionality is not required. SOAP is more suitable if bandwidth is not an important bottleneck, you want to be able to check message validity and if you require the extra functionality provided by the WS-* standards.
No comments:
Post a Comment