12.2. Using REST in Java

Issuing HTTP GET Requests
The key class here is HttpURLConnection, obtained by invoking openConnection on a URL object. Sadly, openConnection method's signature specifies that it returns the superclass type, URLConnection, and we have to downcast the result.

The following method issues a request and returns the entire response as one long string:

public static String httpGet(String urlStr) throws IOException {
  URL url = new URL(urlStr);
  HttpURLConnection conn =
      (HttpURLConnection) url.openConnection();

  if (conn.getResponseCode() != 200) {
    throw new IOException(conn.getResponseMessage());
  }

  // Buffer the result into a string
  BufferedReader rd = new BufferedReader(
      new InputStreamReader(conn.getInputStream()));
  StringBuilder sb = new StringBuilder();
  String line;
  while ((line = rd.readLine()) != null) {
    sb.append(line);
  }
  rd.close();

  conn.disconnect();
  return sb.toString();
}

(This code is very raw; it should be properly padded with try/catch/finally blocks to ensure the reader is closed, etc.)

Remember that if the request URL includes parameters, they must be properly encoded (e.g., a space is %20, etc.). The class URLEncoder can be used to perform this encoding.

Issuing HTTP POST Requests
URL encoding is also required for POST requests, as shown in the following method:

public static String httpPost(String urlStr, String[] paramName,
String[] paramVal) throws Exception {
  URL url = new URL(urlStr);
  HttpURLConnection conn =
      (HttpURLConnection) url.openConnection();
  conn.setRequestMethod("POST");
  conn.setDoOutput(true);
  conn.setDoInput(true);
  conn.setUseCaches(false);
  conn.setAllowUserInteraction(false);
  conn.setRequestProperty("Content-Type",
      "application/x-www-form-urlencoded");

  // Create the form content
  OutputStream out = conn.getOutputStream();
  Writer writer = new OutputStreamWriter(out, "UTF-8");
  for (int i = 0; i < paramName.length; i++) {
    writer.write(paramName[i]);
    writer.write("=");
    writer.write(URLEncoder.encode(paramVal[i], "UTF-8"));
    writer.write("&");
  }
  writer.close();
  out.close();

  if (conn.getResponseCode() != 200) {
    throw new IOException(conn.getResponseMessage());
  }

  // Buffer the result into a string
  BufferedReader rd = new BufferedReader(
      new InputStreamReader(conn.getInputStream()));
  StringBuilder sb = new StringBuilder();
  String line;
  while ((line = rd.readLine()) != null) {
    sb.append(line);
  }
  rd.close();

  conn.disconnect();
  return sb.toString();
}

As you can see, it's not a pretty sight (and that's before adding proper try/catch/finally structures). The problem is that, out of the box, Java's support for handling web connections is pretty low-level.

A good solution can be found in the popular Apache Commons library, and in particular the httpclient set of packages. See Yahoo! guide to REST with Java for details and examples. The documentation covers several interesting extras, such as caching.

23 comments:

Naga said...

The example shows making a request to read the rest response. Can you please add some examples on generating the response content for the said url?

Dr. M. Elkstein said...

Hello Naga,

There's the question of how to generate a response, and of what to put in the response.

The responses are generated by a web server. So, for "how", there are multiple alternatives in Java; for example, one could use Tomcat, or JBoss, and Servlets, or JSPs, or any other templating engine, or generate output directly without templates (which is often more appropriate for JSON and XML responses), etc.

For "what", this really depends on your application. For example, if the REST request is for information about an item from the catalog, the response can be an XML representation of that item (see, for example, REST server responses in this tutorial).

Martin Wildam said...

You don't mention jersey - I found on the net indicators that the easiest way to consume a RESTful web service is to use JAX-RS / Jersey - but unfortunately I did not find yet a good example showing such an implementation. What is your opinion - whould I prefer to use the plain method or use such other libraries on top?

Martin Wildam said...

RESTlet also seems a library/framework for RESTful web services. Thanks to your tutorial I started to think REST is easy but even if it is intended to be easy, thinking about a concrete implementation I get unsure about the proper way using the newest technologies.

Dr. M. Elkstein said...

Hi Martin,

I'm not familiar with the frameworks you mention -- my apologies. In general, with REST, I'd go for the most lightweight framework I could find; but that's just a rule-of-thumb, and the real answer depends on your specific project requirements.

Martin Wildam said...

Thank you for your response. Not sure about what you mean with "lightweight". I am considering my whole applications to be lightweight - even servers and clients.

I feel the Java application server stack sometimes like a ball and chain.

From that point of view Restlet seems to be attractive because bringing everything with it. On the other hand I read about "compatibility" issues in relation to jersey.

Here are a few interesting links:
- Re: Restlet vs other 'rest' frameworks questions/views
http://www.mail-archive.com/discuss@restlet.tigris.org/msg07028.html

- Re: Restlet vs RestEasy
http://www.mail-archive.com/discuss@restlet.tigris.org/msg07565.html

- Which is the best Java REST API - Restlet or Jersey? - Stack Overflow
http://stackoverflow.com/questions/1710199/which-is-the-best-java-rest-api-restlet-or-jersey

- Nabble - Restlet Discuss - Restlet vs. Jersey
http://n2.nabble.com/Restlet-vs-Jersey-td3521911.html

- Nabble - Restlet Discuss - Restlet vs other 'rest' frameworks questions/views
http://n2.nabble.com/Restlet-vs-other-rest-frameworks-questions-views-td2199219.html

- Restlet - Features
http://www.restlet.org/about/features

I tend to choose Restlet over Jersey - those two are my final candidates - but I will go for lunch now and decide then.

Martin Wildam said...

Currently I need to write a REST-Client and I started with RESTlet. Although it might be a good choice when implementing REST services, I decided (after already done the first steps) to change and return to root method(s) as described in your wonderful Tutorial here.

You said: "In general, with REST, I'd go for the most lightweight framework I could find". - This is in fact an experience I made for other components too. - Maybe just "lightweight" should be replaced with "straightforward".

Indicator Veritatis said...

The Java 5 API on classes URI and URL do not recommend using URLEncoder for this purpose.

In fact, URLEncoder does a slightly different kind of 'encoding' HTML encoding. But the RFC calls for URL scaping, not HTML encoding.

The recommended approach is to use a URI constructer, then convert to URL using toUrl.

But not every UIR constructor is equally suitable for this either. The single-argument constructor does no encoding, so any of the other constructors should be used instead.

This will take care of the URL encoding correctly, adding only a slight burden of handling one more Exception.

Igor Polevoy said...

I was compelled to write a simple REST client:

http://igorpolevoy.blogspot.com/2011/01/java-rest-with-ease.html

thanks

Igor

dharan said...

Really good work.Thanks.

Matthew Cornell said...

Super helpful!

I_resent_having_to_name_everything said...

Throwing exceptions on response codes that aren't 200 is a horrible fucking idea.

I can't think of a response to a POST that isn't going to be a 301, or one of the *OTHER* 2xx codes.

Indicator Veritatis said...

I_resent_having_to_name_everything makes a legitimate point, even if the language is off-putting;) But this tutorial is following the recent trend of many tutorials -- offering very 'raw' (the author's own word) code that is nowhere near production quality. It is up to the student to add that.

Then again, as the author again admits, the standard Java packages have pretty cruddy HTTP support anyway; serious production code with use Apache's package instead. So it is a good thing he gives a reference to an Apache tutorial that also takes the reader to the next level in REST as well.

Bidyut Bikash said...

Hi Mr ELKSTEIN,
I'm a rookie in web services. So feel free to point out the if I state something wrong here.

For a project we need to use springMVC to serve as a middle layer between druple/PHP client and a core Java object. In addition, REST will be the architecture.

Now I can't be able to visualize the whole scenario, how things will be connected and what additional API/softwares will be required.

Robert Morschel said...

Hi Mike,

If you're interested in a server-side REST sample using the Spring framework, check out http://soaprobe.blogspot.co.uk/2012/10/soa-rest-spring-framework-example-guide.html.

Vipan Makkar said...

I am using WebSphere in multi tier environment. The WebSphere plugin which is on webserver pass the request to Appserver based on the application context.
When I use REST calls, those are not defined as context and they fail. How does REST work on J2EE with multi tier environment.

Lokesh Gupta said...

JBOSS provides best support for developing REST APIs. I tried with JBOSS 7.1 and below are my results:

http://howtodoinjava.com/2012/11/26/writing-restful-webservices-with-hateoas-using-jax-rs-and-jaxb-in-java/

vishal said...

Hi,
Is there an example of posting XML object (not .xml file) to a resteasy web service?
I tried but i got error with sending xml data, everytime:
org.xml.sax.SAXParseException: Content is not allowed in prolog.
Even though i build my xml from scratch.(so there's not unwanted characters at the beginning of the file)

Srijani Ghosh said...

Hi All,
I will suggest to go through this blog .This worked for me. This blog contains the code snippet for web services which retunrs XML & JSON.

basic web service -
http://javacodingtutorial.blogspot.com/2013/10/creating-web-service-with-maven-jersey.html

web service that returns XML -
http://javacodingtutorial.blogspot.com/2013/10/a-jersey-web-service-that-returns-xml.

A clint that parses XML response -
http://javacodingtutorial.blogspot.com/2013/10/parsing-xml-response-from-webservice-in.html

A webservice that returns JSON & a client that parses JSON -
http://javacodingtutorial.blogspot.com/2013/10/how-to-write-web-service-which-returns.html

Kishore Kumar said...

Hi Elkstein,

I have a requirement to access a secured restful web service url and post some data. Could you please let me know, how to send user credentials to a restful web service.

Elijah said...

So I'm trying to do this as a completely fresh and new Java project. I need to know what are the core libraries that I need to do this tutorial in order to not have code flagged as errors because it is unable to find the libraries that hold the methods which you outline. In addition, I need to know where to download these core libraries from?

Dr. M. Elkstein said...

Hi Elijah,

The example above uses only the standard libraries. Nothing to download or install.

Neutron said...

Very interesting.. So being fairly new to Rest and using Restlet in Action I was wondering how one can store a file/attachment sent from a client via POST/PUT into a local file/folder ?

After creating the Server via:
new MailServerComponent.start();
and creating the root Router:
router router = new Router(getContext()):
router.attach("/attachment/{accountId}/mails".MailServer.class);
return router;

how does one read in an attachment and then stores it into a file locally.
? would you use:

@Put
public void store(String mailRep)...

or use

writer.something....

Thanks