REST APIs and their backend usage

Saturday, September 27, 2014 at 7:36 PM UTC

I don't know how I came across with that today but I found out that even GitHub has a REST API to read data from their services e.g. the profile or repositories of a user. The responses of this API is JSON data:

The data is clearly structured and I wanted to display it in an XPage - but without using client side Javascript. I wanted to get all the data in the backend. My first attempt was to use the built-in JSON capabilities on Domino with the IBM libs but I failed when I wanted to build an object from the retrieved JSON data. If someone can point me to the way then please leave a comment.

Finding the right JSON parser

I am using the Jackson XML/JSON libs here. I know them from my last customer project. These libs are very versatile, but there is one problem: they require the Domino JVM to be set to grant all access rights. To do so, just open the file

[DominoBinaryFolder]\jvm\lib\security\java.policy

and add these lines at the very end

grant {
permission java.security.AllPermission;
};

Save the file and restart your server. After that you are able to bind every lib you want in your application.

First you have to download the Jackson libs from here (you will need all three of them)

You will find the download links on each project page. I downloaded the latest version (2.4). What you will get is three JARs that have to be imported into your application.

Getting the Apache HTTP Client

To retrieve the data from the API URLs I again used the Apache HTTP Client. This is a fast and stable project. Grab your copy of it here:

After importing all the JARs you will end up with something like this:

Creating the models

The key part of the data you will get from the API is to "wrap" it into a Java object. This is how the ObjectMapper from the Jackson lib comes in handy as it does exactly this. If you have a look at the data you get from the GitHub profile API you may see what I mean:

{
"login": "zeromancer1972",
"id": 4763327,
"avatar_url": "https://avatars.githubusercontent.com/u/4763327?v=2",
"gravatar_id": "",
"url": "https://api.github.com/users/zeromancer1972",
"html_url": "https://github.com/zeromancer1972",
"followers_url": "https://api.github.com/users/zeromancer1972/followers",
"following_url": "https://api.github.com/users/zeromancer1972/following{/other_user}",
"gists_url": "https://api.github.com/users/zeromancer1972/gists{/gist_id}",
"starred_url": "https://api.github.com/users/zeromancer1972/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/zeromancer1972/subscriptions",
"organizations_url": "https://api.github.com/users/zeromancer1972/orgs",
"repos_url": "https://api.github.com/users/zeromancer1972/repos",
"events_url": "https://api.github.com/users/zeromancer1972/events{/privacy}",
"received_events_url": "https://api.github.com/users/zeromancer1972/received_events",
"type": "User",
"site_admin": false,
"public_repos": 15,
"public_gists": 1,
"followers": 1,
"following": 2,
"created_at": "2013-06-21T18:26:42Z",
"updated_at": "2014-09-24T21:03:33Z"
}

The data is flat and consists of fields with different values and types - a perfect set for a Java class!

So I defined a model class with exactly that amount, types and names of the given fields. You usually have to do so. If you leave one field the ObjectMapper will produce an error as it tries to map the JSON value into that field - which can not be found. You can suppress that error with an annotation, I will show that later.

So my class looks like this:

Wow, that's alot of fields! When you look at the data that the "get repos" URL delivers, you can imagine what it would mean to create a class for that! But you don't have to define all the fields but just the ones you want to read. The trick is to use one of the annotations that ship with the Jackson libs. Place this one at the class level of your model class if you want to ommit one or more fields:

@JsonIgnoreProperties(ignoreUnknown = true)

This will suppress the error when the parser doesn't find the right field.

Bean or not (to) bean?

I created a class called GitHubController with some methods to read the data and construct the corresponding objects. This class in my case is a bean as I wanted to accss the data from an XPages view level. This is my faces-config.xml entry for it:

<managed-bean>
    <managed-bean-name>github</managed-bean-name>
    <managed-bean-class>org.openntf.github.xsp.GitHubController
        </managed-bean-class>
    <managed-bean-scope>view</managed-bean-scope>
  </managed-bean>

The class itself uses the HTTP client and delivers two methods for the profile and repos data.

The object is created with the lines

ObjectMapper mapper = new ObjectMapper();
profile = mapper.readValue(rd, GitHubProfile.class);

The next step is to access the data via the bean method called in an XSP panel with a Object Data Source attached to it:

<xp:panel>
        <xp:this.data>
            <xe:objectData var="profile"
                createObject="#{javascript:return github.profile(compositeData.GitHubUserName);}">
            </xe:objectData>
        </xp:this.data>
        <a href="#{javascript:profile.html_url}" target="_blank">
            <xp:image url="#{javascript:profile.avatar_url}" id="image1"
                style="width:100%">
            </xp:image>
        </a>
        <h4>
            <xp:text value="#{javascript:profile.login}"></xp:text>
        </h4>
</xp:panel>

This will show some of the profile data like the avatar picture and the username. It also uses the profile URL to get the image clickable to open the profile page itself. Notice the parameter used in the method of the bean: it reads a value from the compositeData object as I use this one in a custom control where "GitHubUserName" is the name of a custom property.

Finally we get a nice implementation of yet another API to use it in an XPages application. I implemented all of the above in my Bootstrap 3 template. You can find it on - guess what - GitHub as well: https://github.com/zeromancer1972/Bootstrap-3-Template

Last but not least you can see a demo page here that also uses the data from the repos URL: http://mardou.dyndns.org/bs3template.nsf/github.xsp

Update

You can also use the Genson library that also maps an object from your JSON data. This lib is very slim (just 1 JAR) and gives you also the functionality to create your objects like with

profile = new Genson().deserialize(rd, GitHubProfile.class);

You can grab the lib from here: http://owlike.github.io/genson/





Latest comments to this post

Patrick Kwinten wrote on 06.05.2015, 09:43

Hi Oliver

I tried this on my (local) test server that runs in a virtual machine. The problem I have is that I can not establish an internet connection via the server. Accessing an internet address via a web browser works fine.

Do you have any idea how I change the settings for the Domino server to access the internet?

 

 Reply to this comment
 Link to this comment

Leave a comment right here