In my two previous blog posts I have introduced Ratpack and the lightweight ODM layer available in our Java SDK. This post will build up on them and showcase a REST API to manage users through the Couchbase repository.

I want my API to support the four basic HTTP verbs and to support content-type. Everything has been thought out for that in Ratpack. The Chain object is like a builder for composing handlers. So I wrote a new Action class to bind a chain to the 'user' URL prefix. This will simplify my main method a lot:

To make sure my UserHandler instance can be found, I also need to add it to my Config Guice module:

I also add the UserRenderer class that will be used to handle the different content-types.

Custom Renderer

In Ratpack you can register new RendererSupport classes. Their goal is to specify a way to render your T object based on the Context. In my case I want to render a User object based on the context content-type. The Context object gives you a byContent method that allows to compose rendering based on the content-type set in the request. Usual types are predefined already. In my case I just want to support json and text:

The text rendering is just a simple toString(). The JSON version uses the Jackson object available by default in Ratpack. It gives you access to shortcut for JSON/Object conversions. A call to the json method giving the User object as argument will do. Jackson is also used internally by our Java SDK. But there is a trick. The @Field annotation I used for my Couchabse ODM is not picked up by the default Jackson mapper used in Ratpack. So I need to add the Jackson @JsonProperty annotation to compensate. I would not have had to add anything if I did not use the @Field annotation in the first place. I will try to find a better way to make this work but in the meantime it works just fine.

Composing the API with Handlers

I am now in a good position to start working on the API. GET, PUT and DELETE need a user id to work. So the first thing I am doing is checking if there is something after the /user/ URL. Handlers are all chained together and executed in the order you declare them. Once you get in a handler, the chain stops. So you want to make sure you declare /user/:userId before /user/. Path binding uses regex, you'll find examples in the Chain documentation.

Calling the path method allow me to give the path regex and a handler as argument. In the Handler I start by getting the Couchbase repository and the userId from the path tokens. Then I call the byMethod method to define a function for each HTTP verb I need to support. Here I will return a user for GET, update or create a user for PUT and remove the user for REMOVE.

The most interesting verb here is PUT as it requires content form the request. The Context parse method takes a Parse object as argument and returns a Promise. Here I want to parse the JSON from the request and map it to a User object. So it returns a Promise. Since I am an RxJava user I will map that Promise to an Observable, then map the User object to an EntityDocument to finally save it with the Couchbase repository. Than I convert that observable back to a ratpack promise and send back a simple OK string. You might want to do something smarter in real life se cases :)

Once the HTTP verbs that needs a userId are implemented, I can finish with all the others. And I can do that easily with the method all. Here I get the repository and the bucket from the registry. Then for the GET method, since it has no user id, I return the full list of Users. To do so I run a basic N1QL query. Finally the POST is identical to the PUT method.

This may not be a totally RESTFUL API, but should give you a good idea on how easy it is to craft one with Ratpack, Couchbase and RxJava. Please let me know if you want to see more stuff happening around Ratpack, like a Couchbase Module.


Posted by Laurent Doguin, Developer Advocate, Couchbase

Laurent is a Paris based Developer Advocate where he focuses on helping Java developers and the French community. He writes code in Java and blog posts in Markdown. Prior to joining Couchbase he was Nuxeo’s community liaison where he devoted his time and expertise to helping the entire Nuxeo Community become more active and efficient.

Leave a reply