Building RESTful services – part 2

March 26, 2012 3 comments

This is part 2 of “Building RESTful services”.  In Part 1 we talked about Level 1 and Level 2 of the Richardson Maturity Model.

Level 3 – Hypermedia

Hypermedia is really the most interesting aspect of REST and the aspect that is key to scalability and loose coupling. Sadly this is also the aspect that most services that aim to be RESTful have trouble with.

As humans using a web browser, we use this concept every single day. If you wanted to look at the sports section of msn, what do you do ? You type in http://www.msn.com in the browser, look for the hyperlink with the title “sports” and click on it. This concept of hyperlink is so simple, but is one of the most important reasons for the popularity and scalability of the web. Instead of using a hyperlink, imagine if you had to download a “document or a manual” for msn.com that explained the URI to type in to the browser for each section and every time you needed to access something you had to look at the document, find the URI corresponding to your section and type it into the browser. Now imagine if you had to do this for every single website, each having a different kind of document in a different custom format. The internet would certainly not be what it is today. Yet a majority of the APIs built today make us do this. This is where the hypermedia concept comes in.

Let’s say there is a bookstore which has an api for clients to access various lists (e.g. top sellers, new arrivals etc). To get a list of top sellers in the java category, a client may make the following call

GET /estore/lists/topsellers/software/java?count=5

and this returns the following


<books count="5">
 <book purchased="true">
     <id> 12345 </id>
     <title> Effective Java </title>
     <author> Joshua Bloch </author>
 </book>
 <book>
     <id> 23456 </id>
     <title> Java Concurrency </title>
     <author> Brian Goetz </author>
 </book>
...
...
...
 <book>
     <id> 56789 </id>
     <title> Clean Code</title>
     <author> Bob Martin </author>
 </book>
</books>

This would typically be accompanied by documentation such as

Method – Get More Details about a book
Call the following URL
/estore/books/id/

Method - Get Reviews for the book
Call the following URL
/estore/books/id//reviews

Method - Provide a “recommended” rating for the book
Call the following URL. Note that only customers who have purchased the book can provide the recommended rating (purchased flag should be true)
/estore/books/id//rating?level=&customer=

Method - Get Next set of books in the list
Call the following URL
/estore/lists/topsellers/?startIndex=&count=

It is the client’s responsibility to make sure that startIndex and count have the right values.

We’ve all seen API’s built and documented this way. This approach puts the burden of generating the URIs for subsequent actions completely on the client. These are the potential issues with the above approach -

  • Errors in constructing the URIs

The primary responsibility for constructing the URIs rests on the clients, for any action that the client wants to perform based on the list. This is a simple use case, but as things get more complicated, the likelihood of a client constructing the URI incorrectly increases a lot.

  • Tight Coupling

Since the URI formats need to be published and specified ahead of time for the clients to construct them, the service has very little flexibility in terms of changing the API. For example if the service wants to point to a completely different URL for getting reviews,  it would be tough to do so without breaking existing clients.

  • State transitions and business rules on the client side

Let’s say the service changes the business rule and any customer can now provide a rating for the book. This means that all clients that are using the current API now need to change their code to make this happen. This tightly couples business logic to client side code and severely restricts the service’s ability to iterate over business rule changes without massive coordination efforts with all clients.

This is where hypermedia shines. Take a look at the response below with additional hypermedia links (Relative links are used for brevity, but assume all the links are full links including host name)

<books>
 <book purchased="true">
     <id> 12345 </id>
     <title> Effective Java </title>
     <author> Joshua Bloch </author>
     <link rel="moreInfo" href="/estore/catalog/books/id/12345"/>
     <link rel="reviews" href="http:/reviewStore/estore/reviews/id/9912345&customer=888"/>
     <link rel="rating" href="/estore/books/id/12345/rating?customer=888"/>
 </book>
 <book>
     <id> 23456 </id>
     <title> Java Concurrency </title>
     <author> Brian Goetz </author>
     <link rel="moreInfo" href="/estore/catalog/books/id/23456" />
     <link rel="reviews" href="http:/reviewStore/estore/reviews/id/9923456&customer=888" />
 </book>
...
...
...

 <link rel="next" href="/estore/reports/topsellers/software/java?startIndex=6&count=5"/>
</books>

So what’s different here ? We have three new elements which contain a hyperlink with some metadata. Let’s look at each of them

    <link rel="moreInfo"> ... </link>
 Instead of trying to construct the link for more details, the client can simply look at the response for the “moreinfo” tag and if it exists, it knows that there is additional info available. Pretty simple.
    <link rel="reviews"> ... </link>
  Once again, instead of trying to construct the URI, the client looks for the presence of “reviews” link type. Notice that the link to the reviews can now be changed by the service if necessary. Maybe the site decides to consolidate the reviews for all their product line and also decides to track which customers look at reviews and so on. Since the URI is fully generated by the service and the client merely looks for the appropriate hyperlink, not only do the clients not break, they don’t even have to realize that the underlying hyperlink changed.
    <link rel="rating"> ... </link>

If you recall, the initial business rule was that only if the purchased=”true” flag is available, the client should display the rating link to the customer, and a change in this business rule affected the client. Instead, here notice that based on the business logic, the Service can either send back, or not send back a link called “rateBook”. The client simply looks for this link, and if it is not available, doesn’t display the rating link.

Similar benefits are realized by the presence of a “next” link. These  examples highlight the point that by adding hyperlinks to control next steps and NOT making the clients construct URIs, the system as a whole has gained a lot of flexibility.

HATEOAS

    Hypermedia As The Engine Of Application State or HATEOAS refers to allowing clients to navigate through appropriate application states using hyperlinks. The above examples touch on this a little, but let’s look at this from a slightly different point of view. Going back to our eStore example from PART 1, let’s start with an empty order

GET /estore/order/178567

<order>
    <cart>
       <items>
       </items>
       <link rel="update" href="/estore/order/178567/cart"/>
    </cart>
</order>
Note that the link with the type “update”  indicates that the only possible next step for this order is to update the cart by adding more items. The absence of links such as “payment”  or “cancel” imply that those are not valid steps at this point. Let’s say a couple of items get added to the cart by making calls such as
POST /estore/order/178567/cart
<item code="abc" qty="1"/>

//another item
POST /estore/order/178567/cart
<item code="def" qty="1"/>

 Now our order looks something like this

GET /estore/order/178567

<order>
    <cart>
        <items>
            <item code="abc" qty="1">
            <item code="def" qty="1">
        </items>
        <link rel="update" href="/estore/order/178567/cart"/>
    </cart>
    <link rel="saveForLater" href="/estore/customer/1356/archive/order/178567"/>
    <link rel="cancel" href="/estore/order/178567"/>
    <link rel="address" href="/estore/order/178567/address" type="application/vnd.estore_address+xml"/>
</order>

Notice that there are several new links as part of the order itself which indicate one of several next steps that can be done as part of the shopping process.

  •  type=saveForLater
    • The presence of the link of the type “saveForLater” indicates that one valid option for this order is for it to be saved for later, so that the customer can come back to it at some point. Note that if there were no items in the cart, this link would not be available .
  • type=cancel
    • Indicates that this order is in a state where it can be cancelled if the customer wants to, (by making a delete request – this does need to be documented as part of a simple resource documentation). Again, only available for a non empty cart
  • type=address
    • This serves as the link to enter the address for the order so that the checkout process can start.

The important point here is that the client doesn’t have to figure out from an external document as to what are the possible next states for the order. The possible next states are all captured with hyperlinks. Again, this makes for really loose coupling and provides the service a lot of flexibility in evolving business rules around Order processing without breaking existing clients. Also note that each of the link types either returns or accepts a certain content-type. While it is tempting to use application/xml, a specific format such as application/vnd.estore_order+xml, or application/vnd.estore_address+xml is preferred. Another important thing to keep in mind is that while the client is expected to use the hyperlinks from the response, the service should still guard against invalid requests for a given state.

Let’s go one more step, and assume that the customer decided to enter the address for the order.

POST /estore/order/178567/address
<address>
    <street> ... </street>
    <zip> ... </zip>
     etc etc
</address>
Now that the address for the order has been entered, let’s see what can be done with the order now.
GET /estore/order/178567
<order>
    <link rel="cart" href="/estore/order/178567/cart"/>
    <link rel="saveForLater" href="estore/customer/1356/archive/order/178567"/>
    <link rel="cancel" href="/estore/order/178567"/>
    <link rel="address" href="/estore/order/178567/address"/>
    <link rel="payment" href="/estore/order/178567/payment"/>
</order>
  • Payment
    • The presence of the link of the type “payment”  indicates that payment is a valid next step for the order in its current state. If the cart was empty with no items, or if there was no address associated with an order, our made up business rules wouldn’t have allowed us to enter payment information. But now, based on the link, the customer can proceed to payment
As you can see, the set of possible next steps are provided by the service at any given point using hyperlinks. This is HATEOAS. Now assuming the payment information was provided and successfully validated, the order now goes into a state where the only possibility is to cancel the order ( since our made up business rules allow for an order to be cancelled till it ships)
GET /estore/order/178567
<order>
    <link rel="cart" href="/estore/order/178567/cart"/>
    <link rel="cancel" href="/estore/order/178567"/>
</order>

Allowing clients to dynamically discover  next logical steps using hyperlinks, instead of upfront specification is a key part of RESTful design. Thinking in this way helps us realize a lot of benefits of  RESTful services. Finally, taking this point further, it makes a lot of sense to expose only the stable starting point for a service, and allow clients to discover capabilities on the fly. For example, our eStore could simply advertise the  well-known URI /estore/ and everything else is simply discovered by the client by following relevant links provided by the service at the right time.

GET /estore/
<estore>
   // Get current specials
   <link rel="specials" href="/estore/specials"/>
   // Starting point for all catalog related info
   <link rel="catalog" href="/estore/catalog"/>
   // POST to start a new order
   <link rel="order" href="/estore/order"/>
   // Starting point for all customer specific interaction including login
   <link rel="profile" href="/estore/customer"/>
</estore>

Conclusion

While the concept of hypermedia is simple, it is the one aspect that people building RESTful services ignore most often. Using hypermedia is really significant in making a web service loosely coupled and highly flexible, allowing it to evolve over time without breaking clients.

References

  1. http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  2. http://www.crummy.com/writing/speaking/2008-QCon/act3.html
  3. http://en.wikipedia.org/wiki/Representational_state_transfer
  4. http://www.infoq.com/articles/rest-introduction
  5. http://restinpractice.com/default.aspx
Categories: REST

Building RESTful Services – Part 1

November 1, 2011 6 comments

    Over the last few years REST adoption has seen tremendous growth. It is fast becoming the defacto standard for exposing a service to client applications over the web. Often however several services that attempt to be RESTful miss out on the benefits of using REST due to not looking past the basic concepts. There are significant benefits to both the service provider and the service consumer when an API is built and consumed RESTfully but in order to realize those benefits one has to understand and embrace all its principles. This is a three-part article structured as follows

Part 1 – Basics and the importance of leveraging the HTTP protocol
Part 2 – Importance of hypermedia in a RESTful service (HATEOAS)
Part 3 – Practical Issues in building a RESTful service

Shift in Thinking

The Web as a Platform

    The web as it exists today consists of several building blocks such as user-agents, intermediaries such as various types of proxy servers, the web server , the http protocol and so on. A key REST concept involves treating this web infrastructure as a platform on which applications and APIs can be built on. Previous approaches such as WS* and SOAP have largely ignored the web and the protocol followed by the web (http). They simply use http as a transport protocol. A RESTful web service on the other hand understands the role played by each component of the web and uses them as building blocks. Another interesting way to look at this concept of embracing the web fully is by looking at the Richardson Maturity Model . This model gives us a structured way of looking at the degree to which a web services leverages the web infrastructure as building blocks. The higher your service is on the RMM scale, the more it leverages the web. That said, Level1 and Level2 of this scale are really prerequisites to get to level 3, which is where the real power, flexibility and scalability of RESTful services are realized. Furthermore one could easily argue that according to Fielding, without using hypermedia (Level3) a service is really not RESTful.

Thinking in Resources

    The other key concept in REST is to think in terms of resources that can be manipulated using a fixed set of methods (HTTP Verbs)  instead of thinking in terms of custom RPC methods exposed over http. We are used to modeling our business API in terms of several custom methods that can be invoked remotely. The RESTful way of modeling is to look at our business API in terms of Uniquely identifiable resources which can be manipulated using the http verbs. Let’s say we are dealing with a catalog system. Traditionally we would have several methods such as

http://server/estore/createCatalogItem,
http://server/estore/estore/editCatalogItem,
http://server/estore/estore/getCatalogItemDetails,
http://server/estore/
estore/addReviewToCatalogItem,
http://server/estore/estore/addReviewToCatalogItem,
etc.

In a RESTful model, we would identify the key business “resources” as  

http://server/estore/catalog/item/12345
http://server/estore/catalog/item/12345/reviews

and clients would manipulate these resources using the well-known set of http verbs such as PUT, POST, GET  and DELETE (maybe a couple of others if required).  Similarly, an email system can look at a user’s inbox messages as resources that can be manipulated

http://server/mail/folder/inbox/message/id  (GET, POST, PUT and DELETE can be invoked on this message)

This conforms to how the web as a platform works, and makes the interface a lot more structured.

Doing REST Right

    While there are several parts to doing REST right, this article attempts to stick in general with the Richardson Maturity Model to stress the importance of leveraging the web. While Level zero and Level one services don’t really get us anywhere, we’ll take a quick look at them to mainly highlight what services at these levels are  NOT doing right!! .

RMM Level Zero

    Services in this category don’t really make use the web as a platform since they don’t use any aspect of the web. Consider for example SOAP based web services (WS*). These typically expose a single URI and use a single http verb (POST). Services at this level simply use http to send a payload which dictates all aspects of what the client or server would do. Consider a SOAP based shopping web service which provides a generic endpoint, and all operations are made by the client by doing an HTTP POST against that end point.

POST /estore/ShoppingService HTTP/ 1.1 Content-Length : zzz
<request>
 <method name="getItemsOnSale">
     <param name="dept" value="electronics"/>
     <param name="count" value="15"/>
 </method>
</request>

This would then return a response with a list of items on sale in the electronics department. Similarly another method to add one of those sale items to the cart would look like

POST /estore/ShoppingService HTTP/ 1.1 Content-Length : zzz
<request>
    <method name="addItemToCart">
        <param name="itemId" value="123456789"/>
    </method>
</request>

Notice that nothing in the http protocol is used by the client or the server at an application level. All the information required to fulfill the operations is self-contained in the payload. You could be passing the exact same messages over TCP sockets and the client and server would work exactly the same way. Http is that dispensable here !!.

RMM Level 1 – Using Unique Identifiers

    Services at this level use URIs to uniquely identify resources. Instead of making every request to the same endpoint,  requests are made to specific endpoints. These services leverage one important aspect of the web – each resource should be uniquely identifiable. So the request to get the Items on Sale becomes


POST /estore/getSaleItems ( typical POX implementations use POST everywhere and pass parameters in the request body)
<request>
    <param name= "dept" value= "electronics" >
    <param name= "count" value= "15" >
</request>

Note that this could be POST or GET. In level 1 no conscious decision is made as to whether GET/POST should be used since the http protocol itself is not necessarily respected here. The call made to add an item to the cart would now look like

GET (or POST)
/estore/addItemToCart?itemId=123456789
<order>
    <cart>
        <items>
            <item code="abc" qty="1">
        </items>
    </cart>
</order>

Notice that making separate identifiable resources (yes they don’t look like resources, but that’s just the way we named them) eliminates the need to pass some information in the xml payload since this information is now taken care of in the identity of the URL called. So we don’t have to pass methodName=getSaleItems or methodName=addItemToCart anymore. Even though Level 1 services use a unique URI for services, they typically don’t make use of the http protocol in any way, and aren’t something to strive for as an end goal.

RMM Level 2 – Respecting the protocol (HTTP)

    This section goes over various aspects of the HTTP protocol that play an important role in REST. There is an existing ecosystem consisting of millions of servers, and programs and user-agents all of which already understand HTTP. A RESTful approach to building services makes the case that by respecting the http protocol all this existing infrastructure can help our application scale. In the past we have been trained to think in terms of keeping the protocol and the data separate – we have always strived to keep our message payload protocol agnostic. We would in the past try very hard to build our system such that the same message payload could be used with http, tcp/ip asynchronous messaging etc. However in a RESTful system, http is NOT a transport protocol, but an application protocol. The http verb used to make requests and the http headers are a critical part of this application protocol. Several important concepts are conveyed via the headers (e.g. status code, content type, caching etc). Failure to adhere to this application protocol means that our application does not speak the language that all the user-agents and intermediaries understand and hence won’t be able to effectively leverage them as building blocks. This is a very broad area, but in general can be categorized into two general buckets

  • Using the right http verb
  • The importance of Http Headers (including status codes)

Getting the verb right

    There are 4 commonly used http verbs (GET, POST, PUT, DELETE) and others that are not used as often such as HEAD , OPTIONS etc. Each verb has certain characteristics and it is critical to choose the right verb .

GET

GET should be used only for safe (no side effects for which the client is responsible) and idempotent (can be repeated multiple times with the same result) requests. So GET should not be used to update or delete a resource or to make a new resource. Every system that understands the http protocol assumes that a GET will NOT change the state of the system and hence will make assumptions based on that. For example a client which is not able to make a successful GET request is well within rights to make another attempt for the exact same request and see if the request can be fulfilled. So if GET is used for requests which are not safe there could be serious consequences. Consider for example a scenario where GET is used to add an item to an online shopping cart. Let’s say the item was added successfully on the back-end but due to a flaky connection, the client doesn’t get a success response. An abiding http user-agent (such as a browser or many of the http client libraries) will retry the request since GET is supposed to be safe and idempotent. Now we have a situation where the item exists in the cart twice even though the user wanted to add it only once.

Not using GET for safe idempotent requests also has undesired consequences. These mainly involve caching which are less serious functionally but could be serious with respect to scalability. In general, responses to GET requests can be cached by the client, proxies etc which is extremely critical from a performance and scalability point of view. There are lots of use cases where having a proxy server or the user’s browser cache the result of a request (could be data or things like images) would save a trip to the server resulting in saved computing power as well as saved bandwidth. Not using GET for such requests would result in a serious loss in scalability.

POST

POST can be used to either create a resource or update a resource. All http aware components assume that POST will make a change to the state of the system (not safe) and will not repeat a POST request in case of an error. For example any time you are submitting an order online and hit the submit button for the second time, the browser will prompt you to confirm that you really did want to make the request a second time, since POST is not idempotent. POST can also be used to create a resource but more about that a little later.

PUT

PUT is an important part of HTTP but due to not being part of HTML forms, a lot of people shy away from using PUT. PUT creates a resource for the URI specified by the client with the information in the request. If the resource already exists, PUT simply replaces what existed with the new information. Because of this, PUT is idempotent as long as the client uses it the right way ( with complete information as part of the request and not just a partial update) . If the same PUT call is made twice, the previous resource will simply be replaced by the same resource again.

PUT vs POST

There are two factors that determine whether PUT or POST should be used for creating or modifying a resource.

1. Who owns the URI identity  ?

    This is relevant while creating a new resource. Anytime the client is responsible and aware of the complete URI where the resource needs to be created, PUT can be used. However, often the client will not know the URI of the resource (since it may be generated by the server). Here using PUT is not possible and a POST needs to be used. For example a new online shopping trip for a customer may be tracked by an id generated by the server. When the first item is added to the cart, a new Cart resource is created by the server with a generated unique identifier as the cart id, which is part of the unique URI for the cart. The client will make a POST request with the required information and the server on creating the resource will use the Location header to send back the URI of the newly created resource.

POST /estore/order/

results in a new order created with id 178567 , and the server sends back the complete URI for the newly created resource in the location header

200 OK
Location : /estore/order/178567

From this point onwards, the client can manipulate the URI returned in the Location header. So in general while creating a new resource, if the client owns the URI identify, then PUT should be used, otherwise POST is the only option.

2. Partial updates vs full replacement.

    This is relevant for updating an existing resource. Once the client is aware of the URI of a resource (from the location header after resource creation) and wants to update the resource, it has two options. One is to use PUT and send the complete representation of the new resource. The other is to just send the delta. Sending a delta is often the more practical option (e.g. sending the item added to the cart instead of sending the entire cart + the extra item) and is a lot simpler on the client. The other reason why deltas are more practical is that a full resource representation involves hypermedia links which we really don’t want to be shipping back and forth between the client and server (more about hypermedia later). Now recall that a PUT request simply replaces the current resource with the new value. Hence PUT is not really suitable for sending deltas.  So anytime we operate under the assumption that only deltas to the resource are being sent, the right method to use is the POST method (at least till the “PATCH” method garners more support).

Let’s look at the same example as earlier where a new cart was created with one item

GET  /estore/order/178567
<order>
    <cart>
        <items>
            <item code="abc" qty="1">
        </items>
    </cart>
</order>

Now lets say the client wants to add another item to the cart. The client could do a PUT with the representation of the entire cart,

PUT /estore/order/178567
<order>
    <cart>
        <items>
            <item code="abc" qty="1"/>
	    <item code="def" qty="1"/>
	</items>
    </cart>
</order>

or the client could make a POST request with just the additional item such as

POST /estore/order/178567
<order>
    <cart>
	<items>
	    <item code="def" qty="1"/>
	</items>
    </cart>
</order>

The server would interpret this request as a delta request and add the new item to the existing cart.

So in either scenario, the current cart state is

GET /estore/order/178567
<order>
    <cart>
	<items>
		<item code="abc" qty="1">
		<item code="def" qty="1">
	</items>
    </cart>
</order>

Obviously, as the number of items in the cart starts increasing, the PUT to replace the entire cart isn’t that efficient or appealing.

 DELETE

DELETE /estore/order/178567

This asks the server to do a logical delete of the resource. It is important to realize that this is a logical delete. The server can certainly move the existing order to archive, so that the order can now be accessed as

 GET /estore/archive/order/178567

and the original request that we were using,

 GET /estore/order/178567 

would now result in a 404 Not Found.

Content Negotiation

    A really key concept in REST is the idea that what is being exchanged between the client and server is a representation of the resource. It is certainly possible for different clients to ask for different representation of the same resource. For example, a mobile client may prefer to get JSON as the response format, while a web browser may prefer a pdf and some other client may only want xml. If the server decides to support multiple representations, then the same data can be presented in different formats. One way of doing this is to simply pass the type of response desired using a parameter such as


GET /eshop/sales/topItems/monday?format=json
GET /eshop/sales/topItems/monday?format=pdf
GET /eshop/sales/topItems/monday?format=xml

However this ignores the robust existing mechanism for “content negotiation” which is part of http. Embedding the content type in the URI in a non standard manner means that the url links are now not portable. If a person emails a link to the report from the web browser (which displays pdf) to the mobile phone (which expects json), the client needs to do ugly manipulations to the URI to convert the pdf request to a json request. Instead a much better way of dealing with multiple representations is to use the Accept and Content-Type headers which is well understood by all http clients. For example

The mobile request wanting JSON back would look like

Accept: text/json
GET /eshop/sales/topItems/monday

 and the web browser request which wants pdf would send

Accept: application/pdf GET
/eshop/sales/topItems/monday

Now the link can be passed around from one client to another and since the URI is unique, each client can use the http headers to tell the server what it can accept. Imagine another scenario where a client prefers a certain format, but is willing to degrade to a different format if the first one is not available. This is especially true in case of mobile clients. Handling this via the Accept header makes use of a well defined existing mechanism which all user agents and servers already understand and execute. No need for custom logic that needs to be reinvented every time.

Error Handling and Status


Anytime we write an API we are trained to send status codes and error codes. How often have we seen xml like this


200 OK
<response>
<statusCode>AE1987</statusCode>
<errorCode>Authorization Failure </errorCode>
</response>

Think about the thousands of APIs out there each having a custom way of doing this, reinventing the wheel every time. Further more, none of the intermediaries involved (proxies, etc) know that this is a response not worth caching, since they are all trained to look at the Http Status code (which in this case is 200, OK). The http protocol has a variety of status codes. For example


2xx status code = success
3xx status code = additional action is required by the client to finish the request
4xx status code = client has made an error and may need to modify the request before retrying
5xx status code = server is having problems handling the request

REST API developers should look here at the status codes to understand each error code and incorporate them in the API. Here are a few examples of how a a RESTful API should use them


200 OK                  - This should be used only for success and nothing else. Period.
201 Created             - This should be used as a response to a POST request when a resource is created. The location header should contain the URI to the newly created resource
202 Accepted            - This can be used for async processing, with a link to the status/next step being sent by the server.
400 Bad Request         - This can be used for input validation errors.
403 Forbidden           - Return this in case of an authentication error instead of returning a 200
405 Method Not Allowed  - If there is a read only resource and a client makes a non GET request, this should be the status code returned by the server with the valid methods included as part of the Allow header
412 precondition        - This can be used to indicate that a logical precondition check has failed

To summarize, the only status codes that are understood by the http clients as well as various intermediaries, are the http status codes. So misusing these status codes results in not being able to make use of the web infrastructure effectively.

Caching / Scalability


Caching and making use of intermediate servers for caching is critical to the scalability of a RESTful system. There are a wide range of http headers, both on the request as well as response side which heavily influence caching and performance and should be used appropriately. For example if the weather report for a day can be safely cached till the next update arrives, the weather service API in it’s response can indicate that using the appropriate http header . Some commonly used headers that can be used for smart caching include

Expires

    This header in the response gives the time when the response should be considered stale. For example “Expires: Thu, 02 Jun 2011 16:00:00 GMT” tells not just the client but all other intermediaries as to how long to cache the response.

ETag

    More about the ETag can be found here but to summarize, it serves as a way for caching, as well as a way to deal with optimistic concurrency. With each response, the server may send an ETag (Entity tag). Consider for example some large amounts of data that doesn’t change too often and hence is cached by the client.

GET /server/someLargeData

The response contains the header ETag : “123456″

Now if the client wants to refresh the data, it can make a request as follows

GET /server/someLargeData
If-None-Match:

    This will make the server return the complete large response, only if something caused the resource to change on the server (and hence have a new ETag different from the old one) . There are multiple ways to generate an ETag , such as using some hash of the data, or even a timestamp – something which changes every time the resource changes.

    Another use of the ETag is to use it with the If-Match header in the request. Consider for example the possibility of a resource being edited by multiple users at the same time. In this scenario, the client simply checks for the right ETag, and if the ETag has changed, can tell the user that the resource has changed ,refresh with the latest data and ask the user to retry the operation again.

If-Modified-Since / If-Unmodified-Since

This request header can be used to ask the server for content based on modification time. This can help save network resources, similar to the ETag.

Summary

    In this part of the article, we looked at some basic REST concepts, then focussed mainly at the importance of leveraging the HTTP protocol and how various aspects of it can be used in a RESTful web service. The important thing is to not stop here, but go one more step and incorporate hypermedia as an integral part of building web service to truly be RESTful. This will be covered in part 2 of this series.

References

  1. http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  2. http://www.crummy.com/writing/speaking/2008-QCon/act3.html
  3. http://en.wikipedia.org/wiki/Representational_state_transfer
  4. http://www.infoq.com/articles/rest-introduction
  5. http://restinpractice.com/default.aspx

Categories: REST

EJB 3.1 – Asynchronous Methods

April 24, 2011 5 comments

One of the important features in EJB 3.1 is the ability to make asynchronous method calls. While the spec has always prevented spawning of user threads explicitly and still does so, at least now there is a way to achieve asynchronous behavior in a simple way.

Past workarounds

In the past, the most common workaround used to overcome the limitation imposed by the spec involved using  JMS. While JMS plays an important role in applications, it should be really used where messaging is the requirement – either publish/subscribe topics or point-to-point queues. If all you want to do is to make a method call asynchronous, there should be a straightforward way to do this and ejb 3.1 addresses precisely this gap in functionality.

@Asynchronous

It is fairly trivial to make a method asynchronous in ejb 3.1 using annotations. For example


@Asynchronous // This makes all business methods in the class async
public class AsyncProcessor{

    @Asynchronous //To make only this method async
    public void doAsyncStuff(){
    }

}

That’s it.  This is your typical “fire and forget” kind of async behavior where you are not waiting for the method to finish. When the asyncMethod is invoked by the container, it is able to use the @Asynchronous annotation and invoke the method in a different thread. To test this out, here is a test async bean and a caller servlet.


@Stateless
public class AsyncBean {

    @Asynchronous
    public void asyncMethod() {
        System.out.println("start running asyncMethod in thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {  e.printStackTrace();  }
        System.out.println("finished running asyncMethod in thread " + Thread.currentThread().getName());
    }
}

And here is the caller servlet

@WebServlet(name = "AsyncTestServlet",urlPatterns = {"/async"})
public class AsyncTestServlet extends HttpServlet {
    @Inject
    AsyncBean asyncBean;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("caller method running in thread "+Thread.currentThread().getName());
        asyncBean.asyncMethod();
        System.out.println("caller method returned in thread "+Thread.currentThread().getName());
    }
    ...
}

And here is the output from the method calls showing that the async method is called in a different thread.

[#|2011-04-21 21:40:45.591 |INFO|glassfish3.0.1|caller method running in thread http-thread-pool-8080-(1)|#]
[#|2011-04-21 21:40:45.593 |INFO|glassfish3.0.1|caller method returned in thread http-thread-pool-8080-(1)|#] // Calling servlet is done
[#|2011-04-21 21:40:45.597 |INFO|glassfish3.0.1|start running asyncMethod in thread Ejb-Async-Thread-1|#]
[#|2011-04-21 21:40:48.598 |INFO|glassfish3.0.1|finished running asyncMethod in thread Ejb-Async-Thread-1|#]

Note that the ejb async method is called on a different thread “Ejb-Async-Thread-1″, and the simulated three second long method finishes long after the calling servlet thread has finished executing.

Mixing sync and async

There is another possible scenario, where the business method exposed has two parts, an async part and a synchronous part. For example, consider the OrderProcessor class below, which does an initial check to make sure the order is ready to submit, but after that check, it fires off an async method to call a web service (which may take a couple of seconds lets say). If we don’t want the customer to be waiting for the second call, we may try something like this -


@Stateless(name = "OrderProcessorEJB")
public class OrderProcessorBean {
    public void completeOrder(OrderDetails orderDetails){
        System.out.println("start running completeOrder Method in thread " + Thread.currentThread().getName());
        boolean okToProceed=validateOrderDetails (orderDetails);
        if(okToProceed){
            //We want this to happen async, since this may take a while
            submitDetailsToPartnerSite(orderDetails);
        }else{
            throw new InvalidOrderException("Order not valid for reason ...");
        }
        System.out.println("Done with completeOrder Method in thread "+ Thread.currentThread().getName());
    }

    //check here for validity of order before processing - check synchronously
    private boolean validateOrderDetails(String orderDetails){
        System.out.println("start running validateOrderDetails in thread " + Thread.currentThread().getName());
        return true;
    }

    // This may take a couple of seconds, can be done async
    @Asynchronous
    public void submitDetailsToPartnerSite(String orderDetails){
        System.out.println("start running submitDetailsToPartnerSite in thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000); // simulate delay
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Done with submitDetailsToPartnerSite in thread " + Thread.currentThread().getName());
    }

}

And here is the output for the above

[#|2011-04-22T 07:29:29.763|start running completeOrder Method in thread http-thread-pool-8080-(2) |#]
[#|2011-04-22T 07:29:29.763|start running validateOrderDetails in thread http-thread-pool-8080-(2) |#]
[#|2011-04-22T 07:29:29.764|start running submitDetailsToPartnerSite in thread http-thread-pool-8080-(2) |#]
[#|2011-04-22T 07:29:32.764 |Done with submitDetailsToPartnerSite in thread http-thread-pool-8080-(2) |#]
[#|2011-04-22T 07:29:32.764 |Finished completeOrder and returned to customer in thread http-thread-pool-8080-(2)|#] // We wanted this to finish earler !

But that isn’t what we expected! The submitDetailsToPartnerSite  method does not execute asynchronously in spite of the asynchronous annotation. Why does that happen ? When the second method is invoked from the first method, the container doesn’t get a chance to proxy the call to the second method – it is called directly on the same instance and hence executes synchronously. So what do we do to get our desired behavior?. We need to make a little change so that the submitDetailsToPartnerSite method is not directly called, but indirectly so that the container gets a chance to proxy the call. Here is the modified code – the only change is the way the submitDetailsToPartnerSite is invoked from the completeOrder method.


@Stateless(name = "OrderProcessorEJB")
public class OrderProcessorBean {

    @Inject
    SessionContext ctx;

    public void completeOrder(OrderDetails orderDetails){
        System.out.println("start running completeOrder Method in thread " + Thread.currentThread().getName());
        boolean okToProceed=validateOrderDetails (orderDetails);

        if(okToProceed){

            // NOTICE THE CHANGE HERE - INVOKED USING THE ctx INSTEAD of DIRECTLY
            ctx.getBusinessObject(OrderProcessorBean.class).submitDetailsToPartnerSite(orderDetails);

        }else{
            throw new InvalidOrderException("Order not valid for reason ...");
        }
        System.out.println("Done with completeOrder Method in thread "+ Thread.currentThread().getName());
    }

    //check here for validity of order before processing - check synchronously
    private boolean validateOrderDetails(String orderDetails){
        System.out.println("start running validateOrderDetails in thread " + Thread.currentThread().getName());
        return true;
    }

    // This may take a couple of seconds, can be done async
    @Asynchronous
    public void submitDetailsToPartnerSite(String orderDetails){
        System.out.println("start running submitDetailsToPartnerSite in thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000); // simulate delay
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Done with submitDetailsToPartnerSite in thread " + Thread.currentThread().getName());
    }

}

Note that the only code change consists of injecting the SessionContext ctx and using that to call the method as ctx.getBusinessObject(OrderProcessorBean.class).submitDetailsToPartnerSite(orderDetails) . Now this results in the first method getting executed synchronously while the second method getting executed asynchronously, just as we want. Here is the output

[#|2011-04-22T 18:30:59|start running completeOrder Method in thread http-thread-pool-8080-(2)|#]
[#|2011-04-22T 18:30:59|start running validateOrderDetails in thread http-thread-pool-8080-(2)|#]
[#|2011-04-22T 18:30:59|Done with completeOrder Method in thread http-thread-pool-8080-(2)|#]
[#|2011-04-22T 18:30:59|caller method returned in thread http-thread-pool-8080-(2)|#] // Customer Is Not Waiting !
[#|2011-04-22T 18:30:59|start running submitDetailsToPartnerSite in thread Ejb-Async-Thread-2|#]
[#|2011-04-22T 18:31:02|Done with submitDetailsToPartnerSite in thread Ejb-Async-Thread-2|#]

Future

In addition to “fire and forget”, there is also the scenario where we want to fire something off asynchronously, wait for a finite time and check the status, and then do something based on the status. EJB 3.1 takes care of that by providing the familiar Future, which is part of standard java concurrency. Consider the example below where the AsyncService has an asyncMethod which simulates a long running task ( 3 seconds) and returns the result of the task as a Future (Future<T> can be returned). The caller in this case is a servlet which is willing to wait for a second at the most for the async method to return.  The calling servlet simply fires off the asyncMethod, waits for a second and then if the async task is done by that time, uses the returned data. On the other hand if the async task is not done, it can then handle the situation accordingly based on the use case (either show old data, or default data etc). This would be a common use case where due to network issues the response times may vary and we want to take different actions based on a quick response vs slow response.


@Stateless
public class AsyncService {

    @Asynchronous
    public Future asyncMethod(){
    try{
        //simulate long task
        Thread.sleep(3000);
     }catch(Exception e){
         e.printStackTrace();
         return new AsyncResult("Error"); // handle exception

     }
     return new AsyncResult("Meaningful_Result_String");
 }
}

public class AsyncTestServlet extends HttpServlet {

 @Inject
 AsyncService asyncService;

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     Future<String> result=asyncService.asyncMethod();
     try {
         if(result.isDone()){
             //Handle successful fetch
             System.out.println("success - use the result " + result.get());
         }else{
             System.out.println("not yet done");
             //Handle task not finished yet - display cached data etc, based on the use case
         }
     } catch (Exception e) {
        e.printStackTrace();
     }
 }

or do this to wait UP TO 1 second

    try {
        String resultStr=result.get(1, TimeUnit.SECONDS);
        System.out.println(" async task done - resultStr is "+resultStr);
    } catch (TimeoutException e) {
        System.out.println("not yet done");
        //Handle task not finished yet - display cached data etc, based on the use case
    }

If using the first form, be sure to invoke the Future<T>.get() method only after making sure that Future<T>.isDone() is called. If the async task hasn’t finished then the get() method will block, which may not be what you want.! Otherwise use Future.get(timeout,TimeUnit) and catch the TimeoutException. The benefit of using that approach is that you can wait up to 1 second. So if the async method is done earlier, you don’t have to wait the whole 1 second.

Limits

Note that if there are multiple concurrent asynchronous invocations on a bean, there may be a limit to how many the container will allow concurrently. Consider the code sample below


public class AsyncTestServlet extends HttpServlet {
    @Inject
    AsyncService asyncService;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        for(int i=0;i<20;i++){
            asyncService.asyncMethod();
        }
    }
}

On glassfish, after about 16 threads, there was a pause and only after some of those 16 threads finished executing did the remaining 4 threads start. From the caller’s point of view the method calls are still asynchronous, but instead of the async call getting done after 3 seconds (assuming the async task takes 3 seconds), some of the async tasks may get done only 6 seconds after the async method is invoked. This is expected, since the thread pool is finite – so makes sense to experiment with your app server to understand and configure the behavior.

As always, the specs provide the most accurate and best information and it is always a good idea to refer to the specs before using the async behavior for something mission critical.

Categories: EJB, JAVA EE

Improve Performance with http compression

March 10, 2011 1 comment

Over the past few years there has been a huge increase in the number of web services that provide or consume data. As developers optimize their web services for performance and scalability, the one aspect that gets overlooked or is taken for granted is the network bandwidth. As part of optimization adding http compression can have a huge impact on response times. In terms of reward/effort ratio, it is one of the best things to do so that clients capable of handling compression can make use of it. Also since it degrades gracefully, web service clients who are not able to make use of it will continue to work fine.

What to Compress

Most web services expose the data provided by their API as XML / JSON.  If the amount of data exceeds a few KB, it may be worth considering compression. If on the other hand the amount of data you are dealing with is fairly small ( < 2 KB) you may decide that the additional CPU cycles may not be worth it. The answer will obviously vary depending on the specifics of each application and its clients. Also it doesn’t make sense to compress jpg/gif which are already compressed.

Specifics

More often than not an http server such as apache is involved in serving up the content. In case of a java/j2ee application the actual content may be generated by tomcat/glassfish/jboss/websphere but the app server may be behind apache. An option in this case is to let apache do the http compression. All that needs to be done is to enable  mod_deflate and add the right mime types that you want apache to compress. Here is a snippet of what to add to the http conf file. Don’t forget to load mod_deflate .

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/json

As long as the client request includes something like accept-encoding=gzip,deflate , apache will compress the response. The amount of compression taking place can be logged/measured using the DeflateFilterNote directive. Adding something as simple as

DeflateFilterNote Input instream
DeflateFilterNote Output outstream
DeflateFilterNote Ratio ratio
LogFormat "%t \"%r\" %>s %b out=%{outstream}n/in=%{instream}n (%{ratio}n%%)" deflateLog

helps in logging and actually figuring out how much compression is taking place. As the response size increases, the ratio of “compressed data”/”uncompressed data” decreases and can go as low as 5% (savings of 95%).

Here are the log entries for responses roughly 50K ,15K and 5K  in size and the compression levels are seen.

“GET /compression/test.jsp HTTP/1.1″ 200 2687  out=2669/in=51635 (5%)
“GET /compression/test.jsp HTTP/1.1″ 200 1242  out=1224/in=14361 (8%)
“GET /compression/test.jsp HTTP/1.1″ 200 858  out=840/in=5182 (16%)

Glassfish

If your topology demands that there be no apache in front of your app server, compression can be enabled on the app server itself. For example on glassfish (3.0.1) a change from the admin console

Network Config –> Network Listeners –> <listener name >–> HTTP –>Compression (on)

will result in an immediate change.

For tomcat, the change is as simple as adding  compression=”on” in the server.xml for the http connector.

Apache connectors

The above two options take care of compression between the client and the http server.  However in the scenario where apache sits in front of an app server such as tomcat/glassfish (and the two are on physically separate machines),  there is data transfer happening between those machines. Whether or not this data transfer uses compression depends on how apache talks to the app server. Two of the common options for doing this include mod_jk and mod_proxy.

mod_proxy

When mod_proxy is used, the http connector on glassfish (or tomcat ) is used. If gzip compression is enabled on the http connectors as mentioned above , then data from the appserver is compressed and apache mod_deflate will not perform any compression. This can be seen by lines such as these in the apache access log

“GET /compression/test.jsp HTTP/1.1″ 200 1451 out=-/in=- (-%)

On disabling the compression on the app servers, data is uncompressed between apache and the app server, and apache does the compression, which can be verified in the access log.  As mentioned above, adding the DeflateFilterNote gives a lot of useful information to figure out whats going on under the hood.

mod_jk

mod_jk uses a binary protocol and doesn’t explicitly support enabling/disabling compression. Enabling some logging in mod_jk can give more information as to what’s going on. For doing that, we can make use of the JkRequestLogFormat as part of mod_jk configuration

JkWorkersFile     comptest/jk/worker1.properties
JkLogFile     comptest/logs/mod_jk.log
……
JkRequestLogFormat “%w %V %T %b”     #add this line

Here is the output from mod_jk log for scenarios for client requests with/without the gzip,deflate headers and with compression enabled/disabled on apache (using AddOutputFilterByType DEFLATE text/xml text/plain text/html)

[Wed 23:08:02 2011] worker1 localhost 0.015625 9353 ( compression not enabled on apache, client request with gzip,deflate accept-encoding)
[Wed 23:08:02 2011] worker1 localhost 0.015625 9353 ( compression not enabled on apache, client request without gzip,deflate accept-encoding)
[Wed 23:08:02 2011] worker1 localhost 0.015625 9353 ( compression enabled on apache, client request without gzip,deflate accept-encoding)
[Wed 23:08:06 2011] worker1 localhost 0.015625 1799 ( compression enabled on apache, client request with gzip,deflate accept-encoding)

The last column shows the number of types (%b) transferred. Again, note that this log captures the mod_jk traffic details i.e. data between apache and tomcat/glassfish. Looks like as long as compression is enabled on apache and the client request includes the gzip,deflate accept-encoding, there is compression involved in the tomcat-glassfish data transfer.  Same holds for glassfish.

ServletFilter

In scenarios where an embedded servlet container is being used as opposed to a full web container (e.g. embedded jetty) the only option maybe to make use of a ServletFilter that does gzip compression. An example is the gzip filter which is part of jetty.

Client

Double check the http client that you are using to make sure that the right headers are being sent. Requests from javascript libraries are usually pretty good about it, but for java http clients the headers may need to be set explicitly.

Testing

Testing the api to make sure that the compression set up is right is trivial but often forgotten. Something as simple as

curl –compressed -I “webServiceUrl”

and verifying that that the output contains  the header

Content-Encoding: gzip

will ensure that the set up is correct.

Another useful variation to measure the bytes returned is to use

curl -i -w “\nsize= %{size_download}\n” “webServiceUrl”

Trade Offs and Conclusion

Anyone considering using compression should start with the apache mod_deflate , which mentions issues to consider with proxy servers as well as with certain browsers. Applications come in various shapes and forms and there really isn’t a one size fits all solution here. Applications vary with respect to clients, servers, hardware, critical scenarios etc just to mention a few. While there is certainly bandwidth savings as a result of using compression, it comes at the cost of cpu cycles. Given how simple it is to set up compression and try it out, the best way to figure out whether it makes sense for your application is to give it a shot – it might just make a big difference!

Categories: performance
Follow

Get every new post delivered to your Inbox.