.NET Zone is brought to you in partnership with:

Java Solution Architect with over 12 years of experience in Java, J2EE and Open Source technologies. A quest for standardization and creating stable, scalable solutions. Have created core component libraries used by multiples applications/sites in the enterprise and product modules from grounds up. Professional Certifications include (Sun Microsystems Certified Enterprise Architect for J2EE Technology (SCEA), Sun Certified Business Component Developer (SCBCD), Sun Certified Web Component Developer (SCWCD) and Sun Certified Java Programmer (SCJP). Harish has posted 3 posts at DZone. View Full User Profile

Restful Web-Services Best Practices

03.21.2011
| 31457 views |
  • submit to reddit
Some guidelines that I follow while designing the Restful Web-Services (here after referred to as services):


URI Design:

URIs are main part of a web-service interface. It’s painfully hard to change them once services are published and used by internal/external clients. Example URI: /newsletter/{id}/subscription/{sub_id}. URI should
  1. be concise.
  2. be easy to remember.
  3. un-ambiguously identify the target resource.
  4. have only nouns as part of URI. URI should identify the resource not action. HTTP Request Method itself implies action (Get implies search, POST implies create, PUT implies update and Delete implies removal of resource).
  5. Modular. In any non-trivial web-service, number of methods can easily grow to relatively large number (typically many tens) over time. First part of the URI should identify the module (e.g. newsletter, sweepstake, quizpoll, users etc) and all URIs for that module should live under it hierarchically. e.g. invocation of  /newsletter/15 would operate on the newsletter with id 15 and /newsletter/15/subscription/435 would operate on subscription 435 of the newsletter 15.

Versioning:

There will come a time when there will be a new major release of services that may not be backward compatible and we would want to maintain two versions during the period of client upgrade. Versioning should be built into the services from the very beginning as it's hard to introduce once services are published. Client should pass version information in 'Accept' request header (e.g. Accept: application/xml;version=1.0) that server can use. In case version passed is unsupported, server should respond with Http Response Code 415 and an informative message.


Granularity:

Services should be coarse grained. Services will typically map to top level domain objects. In a well designed domain model, operations on top level domain objects will neatly map to business use cases.(Exposing every single persistent object via web-service is not a good practice. It exposes internal application design, adds redundant/un-used services and makes service hard to understand/use) 

Request/Response mime types:

Service should use standard HTTP headers to consume/produce different mime types. That way new content types can be easily supported in future without changing service interface. Content-type headers of the request  determines the type of the content service should expect and accept header of the request should determine the type of response body that services produces.(Typical content-type and accept headers:  application/xml and application/json).

Caching:

Services should cache only successful GET requests. Caching at multiple layers is needed to have good performance. Persistent layer caching is a must. Additionally method level caching can be added. Services should also include cache-control header in response, so client can decide whether or not it can cache the response. Additionally, for cachable responses, server should set HTTP 'Vary' header to indicate that the response is cacheable based on the URL plus the returned Content-Type:
Vary: Content-Type

Logging

Logging should follow one log per request pattern. In a multi user environment, it can be great trouble-shooting help to have one log per request. All logs for the request can be accumulated in request thread and printed once at the end of the request. 

Error Handling:

  1. Service should stick to HTTP Status Codes for communicating success/failure that can be used by program clients. At times it might be necessary to add Custom HTTP Status Codes for very specific use case (these should be an exception and kept to a minimum--to a very few). Any contextual information about the error should be included in reason phrase of HTTP response or custom HTTP response headers.
  2. Service requests involving user entered data (POST, PUT) should additionally include a list of user error messages in the response body that can be used to clearly display to the human users the action needed to correct the error condition. Here I also like to add a new custom HTTP Status code (450) that clearly communicates to the client that it’s user data validation error.

Documentation:

Document should include (for each service method):

  1. HTTP Method
  2. URI
  3. Accept and Content-Type HTTP Request Headers
  4. All possible HTTP Response codes
  5. Any custom Headers
  6. Sample Response
  7. Sample request body  for PUT, POST requests
  8. Schema (xsd files for each request and response)
Published at DZone with permission of its author, Harish Chander.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Olivier Lalonde replied on Mon, 2011/03/21 - 2:03pm

Versionning is best handled with HTTP headers. This way, when using hypermedia, clients can incrementally adjust themselves to the new version and use mixin versions instead of doing batch migration from one version to a new one.

Tomasz Nurkiewicz replied on Mon, 2011/03/21 - 2:52pm

Putting version into the URI gives an impression that we are dealing with different objects (resources) that happen to have common id, while in reality - the resource is the same, only the representation has changed. That's why content negotiation and HTTP headers should be used rather than straightforward URI modification. For the same reason content type (XML/JSON/plain text) should be agreed between the parties based on Content-type header rather than manually crafted extensions in URI (like /product/1.xml).

Harish Chander replied on Thu, 2011/03/24 - 4:15am in response to: Olivier Lalonde

Thanks Tomasz and Olivier for your comments. After much pondering, I agree that passing version number in Header would be preferable to passing it as part of URI. Have incorporated it into the document and updated my previous comments. Thanks!

Chris Valencia replied on Thu, 2011/11/03 - 2:52pm

Thank you for the article. In regards to the versioning discussion, if you do not place the version in the URI how can you have two versions in production at the same time? The first sentence mentions the very common occurrence of having two versions running at the same time while clients update over time. Are you proposing having one service and use the header version to serve up both versions?

Harish Chander replied on Thu, 2011/12/08 - 3:53pm in response to: Chris Valencia

Thanks Chris for your comments. Right, i was proposing passing version information in the header and all calls be served by same end point. End point can process the request differently for each version. This way service can support multiple clients running on different version and clients can migrate to new version at their pace just by changing the version in request header. Versions can potentially be supported at each endpont level. Here is a post that might be useful for adding multiversion support. http://soa.dzone.com/articles/implementing-versioning

Mark Serrano replied on Thu, 2012/02/02 - 8:30am

Interesting compilation of best practices for Restful services. It would be great if you provide some examples as well.

Robert Morschel replied on Mon, 2012/10/08 - 3:15am in response to: Mark Serrano

Check out http://soaprobe.blogspot.co.uk/2012/10/soa-rest-spring-framework-example-guide.html 

 Robert 

Robert Morschel replied on Mon, 2012/10/08 - 3:17am

Good post.  We've been doing commerical REST service development for a number of years now and your observations are pertinent.

For some more detail on our experiences feel free to check out my blog http://soaprobe.blogspot.co.uk/ which talks about concrete REST service guidelines as well as some sample code.

 

Robert 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.