Java: Rest-assured (or Rest-Very-Easy)

Recently I had to write some Java code to consume REST services over HTTP. I’ve decided to use the Client libraries of RestEasy, the framework I use most of the time to expose REST services in Java, since it also implements the official JAX-RS specification. I am very satisfied with the annotation driven approach that the specification defines and it makes exposing REST services a very pleasant task. But unluckily I cannot say that I like the client API the same way. If you are lucky enough to be able to build a proxy client based on the interface implemented by the service, well, that’s not bad:
 
 
 

import org.jboss.resteasy.client.ProxyFactory;
...
// this initialization only needs to be done once per VM
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

SimpleClient client = ProxyFactory.create(MyRestServiceInterface.class, 'http://localhost:8081');
client.myBusinessMethod('hello world');

Having a Proxy client similar to a JAX-WS one is good, I do agree. But most of the time, when we are consuming REST web service we do not have a Java interface to import. All those Twitter, Google or whatever public rest services available out there are just HTTP endpoints. The way to go with RestEasy in these cases is to rely on the RestEasy Manual ClientRequest API:

ClientRequest request = new ClientRequest('http://localhost:8080/some/path');
request.header('custom-header', 'value');

// We're posting XML and a JAXB object
request.body('application/xml', someJaxb);

// we're expecting a String back
ClientResponse<String> response = request.post(String.class);

if (response.getStatus() == 200) // OK!
{
   String str = response.getEntity();
}

That is in my opinion a very verbose way to fetch what is most of the time, just a bunch of strings from the web. And it gets even worse if you need to include Authentication informations:

// Configure HttpClient to authenticate preemptively
// by prepopulating the authentication data cache.

// 1. Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

// 2. Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put('com.bluemonkeydiamond.sippycups', basicAuth);

// 3. Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

// 4. Create client executor and proxy
httpClient = new DefaultHttpClient();
ApacheHttpClient4Executor executor = new ApacheHttpClient4Executor(httpClient, localContext);
client = ProxyFactory.create(BookStoreService.class, url, executor);

I have found that Rest-assured provide a much nicer API to write client invocations. Officially the aim of the project is to create a testing and validating framework; and most of the tutorials out there are covering those aspects, like the recent Heiko Rupp’s one: http://pilhuhn.blogspot.nl/2013/01/testing-rest-apis-with-rest-assured.html. I suggest yout, instead, to use it as a development tool to experiment and write REST invocation very rapidly. What is important to know about rest-assured:

  • it implements a Domain Specific Language thanks to fluid API
  • it is a single Maven dependency
  • it almost completely expose a shared style for both xml and json response objects
  • it relies on Apache Commons Client

So, I’ll show you a bunch of real world use cases and I will leave you with some good link if you want to know more. As most of the DSL on Java, it works better if you import statically the most important objects:

import static   com.jayway.restassured.RestAssured.*;
import static   com.jayway.restassured.matcher.RestAssuredMatchers.*;

Base usage:

get('http://api.twitter.com/1/users/show.xml').asString();

That returns:

<errors>
  <error code="34">Sorry, that page does not exist</error>
</errors>

Uh oh, some error. Yeah, we need to pass some parameter:

with()
    .parameter('screen_name', 'resteasy')
.get('http://api.twitter.com/1/users/show.xml').asString();

That returns:

<user>
  <id>27016395</id>
  <name>Resteasy</name>
  <screen_name>resteasy</screen_name>
  <location></location>
  <profile_image_url>http://a0.twimg.com/sticky/default_profile_images/default_profile_0_normal.png</profile_image_url>
  <profile_image_url_https>https://si0.twimg.com/sticky/default_profile_images/default_profile_0_normal.png</profile_image_url_https>
  <url></url>
  <description>jboss.org/resteasy
 
JBoss/Red Hat REST project</description>
  <protected>false</protected>
  <followers_count>244</followers_count>
  <profile_background_color>C0DEED</profile_background_color>
  <profile_text_color>333333</profile_text_color>
  <profile_link_color>0084B4</profile_link_color>
  <profile_sidebar_fill_color>DDEEF6</profile_sidebar_fill_color>
  <profile_sidebar_border_color>C0DEED</profile_sidebar_border_color>
  <friends_count>1</friends_count>
  <created_at>Fri Mar 27 14:39:52 +0000 2009</created_at>
  <favourites_count>0</favourites_count>
  <utc_offset></utc_offset>
  <time_zone></time_zone>
  <profile_background_image_url>http://a0.twimg.com/images/themes/theme1/bg.png</profile_background_image_url>
  <profile_background_image_url_https>https://si0.twimg.com/images/themes/theme1/bg.png</profile_background_image_url_https>
  <profile_background_tile>false</profile_background_tile>
  <profile_use_background_image>true</profile_use_background_image>
  <geo_enabled>false</geo_enabled>
  <verified>false</verified>
  <statuses_count>8</statuses_count>
  <lang>en</lang>
  <contributors_enabled>false</contributors_enabled>
  <is_translator>false</is_translator>
  <listed_count>21</listed_count>
  <default_profile>true</default_profile>
  <default_profile_image>true</default_profile_image>
...
</user>

Much better! Now, let’s say that we want only a token of this big String XML:

with()
    .parameter('screen_name', 'resteasy')
.get('http://api.twitter.com/1/users/show.xml')
    .path('user.profile_image_url')

And here’s our output:

http://a0.twimg.com/sticky/default_profile_images/default_profile_0_normal.png

What if it was a JSON response?

with()
    .parameter('screen_name', 'resteasy')
.get('http://api.twitter.com/1/users/show.json')

And here’s our output:

{"id":27016395,"id_str":"27016395","name":"Resteasy","screen_name":"resteasy","location":"","url":null,"description":"jboss.org\/resteasy\n\nJBoss\/Red Hat REST project","protected":false,"followers_count":244,"friends_count":1,"listed_count":21,"created_at":"Fri Mar 27 14:39:52 +0000 2009","favourites_count":0,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":false,"statuses_count":8,"lang":"en","status":{"created_at":"Tue Mar 23 14:48:51 +0000 2010","id":10928528312,"id_str":"10928528312","text":"Doing free webinar tomorrow on REST, JAX-RS, RESTEasy, and REST-*.  Only 40 min, so its brief.  http:\/\/tinyurl.com\/yz6xwek","source":"web","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"retweet_count":0,"favorited":false,"retweeted":false},"contributors_enabled":false,"is_translator":false,"profile_background_color":"C0DEED","profile_background_image_url":"http:\/\/a0.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/si0.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/a0.twimg.com\/sticky\/default_profile_images\/default_profile_0_normal.png","profile_image_url_https":"https:\/\/si0.twimg.com\/sticky\/default_profile_images\/default_profile_0_normal.png","profile_link_color":"0084B4","profile_sidebar_border_color":"C0DEED","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"default_profile":true,"default_profile_image":true,"following":null,"follow_request_sent":null,"notifications":null}

And the same interface undestands JSON object navigation. Note that the navigation expression does not include ‘user’ since it was not there in the full json response:

with()
    .parameter('screen_name', 'resteasy')
.get('http://api.twitter.com/1/users/show.json')
    .path('profile_image_url')

And here’s our output:

http://a0.twimg.com/sticky/default_profile_images/default_profile_0_normal.png

Now an example of Path Parameters:

with()
    .parameter('key', 'HomoSapiens')
.get('http://eol.org/api/search/{key}').asString()

Information about the http request:

get('http://api.twitter.com/1/users/show.xml').statusCode();
get('http://api.twitter.com/1/users/show.xml').statusLine();

An example of Basic Authentication:

with()
  .auth().basic('paolo', 'xxxx')
.get('http://localhost:8080/b/secured/hello')
  .statusLine()

An example of Multipart Form Upload

with()
    .multiPart('file', 'test.txt', fileContent.getBytes())
.post('/upload')

Maven dependency:

<dependency>
 <groupid>com.jayway.restassured</groupid>
 <artifactid>rest-assured</artifactid>
 <version>1.4</version>
 <scope>test</scope>
</dependency>

And a Groovy snippet that can be pasted and executed directly in groovyConsole thanks to Grapes fetches the dependencies and add them automatically to the classpath, that shows you JAXB support:

@Grapes([  
    @Grab('com.jayway.restassured:rest-assured:1.7.2')
])
import static   com.jayway.restassured.RestAssured.*
import static   com.jayway.restassured.matcher.RestAssuredMatchers.*
import  javax.xml.bind.annotation.*

@XmlRootElement(name = 'user')
@XmlAccessorType( XmlAccessType.FIELD )
    class TwitterUser {
        String id;
        String name;
        String description;
        String location;

        @Override
        String toString() {
            return 'Id: $id, Name: $name, Description: $description, Location: $location'
        }

    }

println with().parameter('screen_name', 'resteasy').get('http://api.twitter.com/1/users/show.xml').as(TwitterUser.class)

//

This is just a brief list of the features of the library, just you an idea of how easy it is to work with it. For a further examples I suggest you to read the official pages here: https://code.google.com/p/rest-assured/wiki/Usage. Or another good tutorial here with a sample application to play with: http://www.hascode.com/2011/10/testing-restful-web-services-made-easy-using-the-rest-assured-framework
 

Reference: Java: Rest-assured (or Rest-Very-Easy) from our JCG partner Paolo Antinori at the Someday Never Comes blog.

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

One Response to "Java: Rest-assured (or Rest-Very-Easy)"

  1. Ming Li says:

    Good introduction for useful framework, thanks.

    A bug fix for the line 18 in the groovy example:
    return “Id: $id, Name: $name, Description: $description, Location: $location”

    i.e., double quotation mark should be used instead of the single quotation, otherwise, only the format string itself shown in the result.

Leave a Reply


5 × = five



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books