A Busy Developer's Guide to RESTful Services in Java
The beauty of JAX-RS is that it is almost entirely driven by annotations. This means you can turn almost any class into a RESTful service. You can simply turn a POJO into a REST endpoint by annotating it with JSR 311 annotations. Such an annotated POJOs is called a resource class in JAX-RS terms.
Some of the JAX-RS annotations are at the class level, some at the method level and others at the method parameter level. Some are available both at class and method levels. Ultimately the annotations combine to make a given Java method into a RESTful endpoint accessible at an HTTP-based URL. The annotations must specify the following elements:
- The relative path of the Java method - this is accomplished with @Path annotation.
- What the HTTP verb is, i.e. what CRUD operation is being performed - this is done by specifying one of @GET, @PUT, @POST or @DELETE annotations.
- The media type accepted (i.e. the representation format) - @Consumes annotation.
- The media type returned - @Produces annotation.
The two last ones are optional. If omitted, then all media types are
assumed possible. Let's look at a simple example and take it apart:
import javax.ws.rs.*;
@Path("/mail")
@Produces("application/json")
public class EmailService
{
@POST
@Path("/new")
public String sendEmail(@FormParam("subject") String subject,
@FormParam("to") String to,
@FormParam("body") String body) {
return "new email sent";
}
@GET
@Path("/new")
public String getUnread() {
return "[]";
}
@DELETE
@Path("/{id}")
public String deleteEmail(@PathParam("id") int emailid) {
return "delete " + id;
}
@GET
@Path("/export")
@Produces("text/html")
public String exportHtml(@QueryParam("searchString")
@DefaultValue("") String search) {
return "<table><tr>...</tr></table>";
}
}The class define a RESTful interface for a hypothetical HTTP-based email service. The top-level path mail is relative to the root application path. The root application path is associated with the JAX-RS javax.ws.rs.core.Application that you extend to plugin into the runtime environment. Then we've declared with the @Produces annotation that all methods in that service produce JSON. This is just a class-default that one can override for individual methods like we've done in the exportHtml method. The sendMail method defines a typical HTTP post where the content is sent as an HTML form. The intent here would be to post to http://myserver.com/mail/new a form for a new email that should be sent out. As you can see, the API allows you to bind each separate form field to a method parameter. Note also that you have a different method for the exact same path.
If you do
an HTTP get at /mail/new, the Java method annotated with @GET will be called instead. Presumably the semantics of get /mail/new would be to obtain the list of unread emails. Next, note how the path of the deleteEmail
method is parametarized by an integer id of the email to delete. The
curly braces indicate that "id" is actually a parameter. The value of
that parameter is bound to the whatever is annotated with @PathParam("id"). Thus if we do an HTTP delete at http://myserver.com/mail/453 we would be calling the deleteEmail method with argument emailid=453. Finally, the exportHtml method demonstrates how we can get a handle on query parameters. When you annotate a parameter with @QueryParam("x") the value is taken from the HTTP query parameter named x. The @DefaultValue annotation provides a default in case that query parameter is missing. So, calling http://myserver.org/mail/export?searchString=RESTful will call the exportHtml method with a parameter search="RESTful".
To expose this service, first we need to write an implementation of javax.ws.rs.core.Application. That's just a few lines:
public class MyRestApp extends javax.ws.rs.core.Application {
public Set>Class> getClasses() {
HashSet S = new HashSet();
S.add(EmailService.class);
return S;
}
}How this gets plugged into your server depends on your JAX-RS
implementation. Before we leave the API, I should mentioned that there's
more to it. You do have access to a Request and Response objects. You
have annotations to access other contextual information and metadata
like HTTP headers, cookies etc. And you can provide custom serialization
and deserialization between media types and Java objects.
Finally, one must categorize business operation as one of GET, PUT, POST and DELETE. This is probably a bit less intuitive, but it's just a matter of getting used to. For example, instead of thinking about a "Checkout Shopping Cart" operation, think about POSTing a new order. Instead of thinking about a "Login User" operation think about GETing an authentication token. In general, every business operation manipulates some data in some way. Therefore, every business operation can fit into this crude CRUD model. Clearly, most read-only operations should be a GET. However, sometimes you have to send a large chunk of data to the server in which case you should use POST. For example you could post some very time consuming query that require a lot of text to specify. Then the resource you are creating is for example the query result. Another way to decide if you should POST or no is if you have a unique resource identifier. If not, then use POST. Obviously, operations that cause some data to be removed should be a DELETE. The operations that "store" data are PUT and again POST. Deciding between those two is easy: use PUT whenever you are modifying an existing resource for which you have an identifier. Otherwise, use POST.
- The Wikipedia article on REST is not in very good shape, but still a starting point if you want to dig deeper into the conceptual framework.
- Refcard from Dzone.com: http://refcardz.dzone.com/refcardz/rest-foundations-restful#refcard-download-social-buttons-display
- Wink's User Guide seems well written. Since it's an implementation of JAX-RS, it's a good documentation of that technology.
- http://java.dzone.com/articles/putting-java-rest: A fairly good show-and-tell introduction to the JAX-RS API, with a link in there to a more in-depth description of REST concepts by the same author. Worth the read.
- http://jcp.org/en/jsr/detail?id=311: The official JSR 311 page. Download the specification and API Javadocs from there.
- http://jsr311.java.net/nonav/javadoc/index.html: Online access of JSR 311 Javadocs.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Romain Manni-bucau replied on Mon, 2012/10/29 - 1:59am
Billy Clark replied on Wed, 2012/10/31 - 7:16am
Thanks for distilling things, really appreciated!
Your distinction between PUT's and POST's seems both counterintuitive and contrary to specs...I thought PUT's represent the creation of new data and POST's represent a change to existing data.
Is something shifting in those concepts or did you simply get them mixed up?
Again, thanks for taking the time to hit the high points!
Borislav Iordanov replied on Wed, 2012/10/31 - 10:03am
in response to:
Billy Clark
Hi Billy,
Thanks for the nice comments. However, I'd have to disagree that I've mixed up PUT and POST. If something must be added, it's that PUT can be used for creation when the ID of the resource is known. According to the HTTP spec, which is the closest I know to a spec we have for REST, POST creates and PUT updates or creates. The key difference being that in the case of PUT (1) you have to supply the full identifier of the identity being update (or created) and (2) the operation is idempotent which means it can be repeated to the same effect. Both (1) and (2) are important in choosing between PUT and POST. From the, it follows the PUT will create a new resource with the supplied id if one doesn't already exist, and it will do an update of a resource if one already exists. In a POST, on the other hand, usually the identifier of the enclosing resource is specified (e.g. a collection of entities) and if repeated it's not expected to be idempotent. I guess POST can be used to update, yes, for example by updating multiple "child" resources.
In sum, while the distinction may be a bit fuzzy in some cases, in general, given constraints (1) and (2) above, it seems to me that logically PUT is the U while POST is the C of CRUD.
Boris
Borislav Iordanov replied on Wed, 2012/10/31 - 10:53am
in response to:
Romain Manni-bucau
Hi Romain,
Thanks for mentioning that implementation. I believe I'd seen before, but I forget about it when I was writing that post.
Jorge Simao replied on Wed, 2012/10/31 - 11:15am
Answer: AJAX assumes JavaScript...If you don't want to assume that -- i.e. make the webapp work from the functional point-of-view (even if without some sexy features). than doing the work on the server side is better. That is, if you want the application to "degrade gracefully" without JavaScript, or conversely to be "progressively enhanced" with JavaScript.
Good article...
Comparison between different frameworks would also be great..
Cheers,
Jorge.
Billy Clark replied on Wed, 2012/10/31 - 11:39am
in response to:
Borislav Iordanov
I appreciate you're using the HTTP spec and understand the fuzziness better now, I'm onboard with your reason more, thanks for the clarifying!
Richard Youngkin replied on Wed, 2012/10/31 - 8:44pm
in response to:
Borislav Iordanov
Here is an excellent article describing the semantics of PUT vs. POST - http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story.
To elaborate on your explanation a little bit, PUT is a complete replacement of a resource whereas POST can be used to update part of a resource and does not have to be a full replacement. There are also implications WRT web behaviors specified by the HTTP protocol such as caching. But the article above covers all that...
Cheers,
Rich
Omos Aziegbe replied on Thu, 2012/11/01 - 5:09am
Thanks a lot for this article. I thoroughly enjoyed reading this.
Javier Benek replied on Tue, 2012/11/06 - 1:45am
Claude Lalyre replied on Fri, 2012/11/09 - 11:15am
Thanks for sharing this big picture view of REST !
Sanjay Srinivas replied on Wed, 2012/11/21 - 11:21am
Thank you for this article. Really helpful!
Henry Kuhl replied on Wed, 2013/01/09 - 10:47am
Hi Borislav!
Nice article on Restful services. I've been reading random stuff about REST during the last weeks. And in almost every talk and every article, the "architects" state, that HYPERMEDIA aka HATEOAS is one of the key-constraints when designing REST-Services.
Did you miss that point on purpose?
Kind regards
Henry
Borislav Iordanov replied on Wed, 2013/01/09 - 11:31am
in response to:
Henry Kuhl
Hi Henry,
I don't really understand that constraint. When you are designing a REST interface, what do you do to satisfy it? If you retrieve a resource representation in, say, XML that contains some information about another resource not necessarily in the form of a URI, but enough so that the client can construct a URI, does that qualify as hypermedia? In the readings and talks that you've come across, is there an example of a design that doesn't follow the practice and explains how that's bad, then shows the correct version with a good argument why it's better?
Cheers,
Boris
Henry Kuhl replied on Wed, 2013/01/09 - 1:06pm
in response to:
Borislav Iordanov
Hi Boris,
the main idea of HATEOAS IMHO (this looks funny :-) is: you're not hard coding the client against fixed URI's but against relations/resources. These are provided by the server in the header of the response. Applying this to your example, the GET-request to the "/new"-URI would provide information, what other operations are possible from that node.
Watch this talk by Oliver Gierke...it's getting the hypermedia-constraint pretty straight forward.
Additionally, there is something going on regarding an architecture, that is not only RESTful but resource-oriented even on the client side! Here: ROCA-style
Kind regards
Henry
Michael Zaikin replied on Sat, 2013/01/12 - 5:11am
Can you recommend some good book about REST?
Borislav Iordanov replied on Sat, 2013/01/12 - 12:42pm
Sorry, I haven't come across a book that I would recommend. I think there is very good information around the internet :) Good luck!
Victor Homyakov replied on Wed, 2013/01/16 - 4:00am
Typo in code example:
publicSet>Class> getClasses()should be:
publicSet<Class> getClasses()