Monday, 22 July 2013

HTTP Adapters with REST/JSON Services

Using IBM Worklight HTTP Adapters with REST/JSON Services 

Abstract

The IBM Worklight Server provides 'adapters' which can issue requests to web services, databases, and other applications on behalf of mobile device applications.  Adapters can be used to combine information from multiple sources into single responses to mobile devices.  They can also modify data before the request and after the response using server-side javascript, and can even be used to cache freq
uently-requested data.

This introductory tutorial explains how to create and use an HTTP Adapter and mobile application to fetch data from a web service which returns data in JSON format.


Introduction

I recently started using IBM Worklight to build mobile apps.  I needed to write an app which fetches information from a REST service, where the data is returned in JSON format.  I chose to use a server-side HTTP adapter to issue the request, in anticipation of future requirements to fetch additional data from other sources.

To figure out the secrets, I wrote an HTTP adapter which submits an address to the Google Geocoding Service.  This public service returns the latitude and longitude coordinate values (along with a lot of other information) for the address specified in the request.  After the adapter was working on the server, I enhanced my HelloWorklight mobile app to request coordinates for several address locations from the HTTP adapter.
 
 
Architecture

Figure 1 shows a high-level view of the traffic flow.  (a) The mobile app issues a request to the HTTP Adapter which runs in the Worklight Server.  (b) The adapter sends the web request to the backend web service.   (c) The web service returns a response in JSON format to the adapter.   (d) Finally, the adapter returns the response in JSON format to the mobile app.
 
image 

References

The IBM Worklight website has a lot of good tutorials.  I learned everything I needed for this exercise from several tutorials in the section named 'Server-Side Development':

http://www-01.ibm.com/software/mobile-solutions/worklight/library/

The Google Geocoding Service is simple to use.  Requests are of the form: 
    http://maps.googleapis.com/maps/api/geocode/json?address=100 Broadway, New York, NY&sensor=false   
Responses contain a large JSON structure which includes latitude and longitude values.  Complete documentation is here:

https://developers.google.com/maps/documentation/geocoding/


Prereqs

I first set up IBM Worklight in Eclipse on my laptop, created the HelloWorklight project according to the initial tutorials, and installed the resulting APK on my Android mobile phone.  I followed the tutorials in the first two sections here  http://www-01.ibm.com/software/mobile-solutions/worklight/library/  to set up the basic development environment and the Android development environment.


Step 1 of 4. Create a basic HTTP adapter to fetch JSON data from a web service

Start Eclipse.

Right-click HelloWorklightProject-> New-> Worklight Adapter
    Project name:  HelloWorklightProject
    Adapter type:  HTTP Adapter
    Adapter name:  myRESTAdapter

This created several subdirectories and files.

I expanded and edited file HelloWorklightProject-> adapters-> myRESTAdapter-> myRESTAdapter.xml

I changed the 'domain' statement to point to the Google Geocoding Service site:

<domain>maps.googleapis.com</domain>

I listed one procedure.  The term 'procedure' refers to a javascript method in myRESTAdapter-impl.js

<procedure name="getGmapLatLng"/>

I expanded and edited file HelloWorklightProject-> adapters-> myRESTAdapter-> myRESTAdapter-impl.js

I deleted everything in the file and I wrote one small new function.  The function creates an object named 'input' and calls the Worklight Server method invokeHttp().  The path variable was set to point to the Google Geocoding Service:  maps/api/geocode/json'.   The variable 'returnedContentType' was set to 'json', since that is the expected response format from the Google Geocoding Service.  The function accepts an address string as input, which is passed to the Google Geocoding Service as a query parameter.  For example, 'address=100 Broadway, New York, NY'.  A second required parameter is also hard-coded and passed along: 'sensor=false'.

In this initial coding, the method returned the entire large JSON response object, as received from the Google Geocoding Service.

function getGmapLatLng(pAddress) {

    var input = {
        method : 'get',
        returnedContentType : 'json',
        path : 'maps/api/geocode/json',
        parameters : {
            'address' : pAddress,
            'sensor' : 'false'   // hard-coded
        }
    };
  
    return WL.Server.invokeHttp(input);
}

That's it.  Coding of the initial HTTP Adapter is now complete.  It's time to test.


Step 2 of 4. Test the HTTP adapter within Eclipse

IBM Worklight provides a neat ability to test the javascript functions in adapter directly from Eclipse.  Input parameters can be specified manually, simulating values which will eventually be provided by a mobile app.  This lets us debug the adapter in a small environment.

I tested the adapter by expanding HelloWorklightProject-> adapters.   Right-click myRestAdapter-> Run As-> Invoke Worklight Procedure

image

I selected my project, adapter, and javascript method, I typed a physical address (between quotes) in the parameter box, then clicked 'Run'.

image

After a little debugging, I finally got a successful response.  The Worklight 'Invoke Procedure Result' window shows the entire JSON structure returned by the Google API.  It can be scrolled up and down to see more values, including the latitude and longitude I wanted.

image


Success.  This proved that I could issue a request to the web service and get a usable response.


Step 3 of 4. Modify the response data using server-side javascript within the HTTP Adapter

My next step was to extract the latitude and longitude values from the JSON response structure.   The JSON response is huge, and I did not want to send it all to my mobile app.

Aside: For trendy buzzword aficiandos, processing at this point in the overall flow is called 'server-side javascript' processing...

I added some additional javascript in myRESTAdapter-impl.js to drill down into the response JSON and extract the latitude and longitude values:


    // Extract latitude and longitude from the response.
    var type = typeof response
    if ("object" == type) {
        if (true == response["isSuccessful"]) {
          
            // Drill down into the response object.
            var results = response["results"];
            var result = results[0];
            var geometry = result["geometry"];
            var location = geometry["location"];
          
            // Return JSON object with lat and lng.
            return location;
        }
        else {
            // Returning null. Web request was not successful.
            return null;
        }
    }
    else {
        // Returning null. Response is not an object.
        return null;
    }

Repeating the test again showed that the code now returned only the latitude and longitude values, along with a boolean 'isSuccessful'.

image 

The HTTP adapter running on the Worklight server is now ready to be used by a mobile app.


Step 4 of 4. Enhance the HelloWorklight mobile app to fetch the JSON data from the HTTP adapter

I added new functionality to the HelloWorklight mobile app which I had developed previously.   I put everything in the HTML file for convenience.   Here is the code:

In the body section, I added HTML for several buttons.  They list addresses in cities around the world.  The buttons all call one javascript method mobGmapLatLng() in the mobile app.

        Hello Worklight with getGmapLatLng
        <p>
        <button onclick="mobGmapLatLng( '11501 Burnet Rd, Austin, TX, USA' )">Austin, TX, USA</button>
        <p>
        <button onclick="mobGmapLatLng( '4250 South Miami Boulevard, Durham, NC, USA' )">Durham, NC, USA</button>
        <p>
        <button onclick="mobGmapLatLng( '1681 Route des Dolines, 06560 Valbonne, France' )">Valbonne, France</button>
        <p>
        <button onclick="mobGmapLatLng( 'Shefayim 60990, Israel' )">Shefayim, Israel</button>
        <p>
        <button onclick="mobGmapLatLng( '399 Ke Yuan Lu, Shanghai, China' )">Shanghai, China</button>
      

In the head section, I added a new javascript function mobGmapLatLng.  This method invokes the Worklight Client API function 'invokeProcedure()' on the mobile device.  This function calls into the Worklight Server, and connects the request to my javascript method getGmapLatLng() in the HTTP Adapter.   I specified the name of the adapter, name of the function (aka procedure), and the address parameter in object 'invocationData':

                function mobGmapLatLng(pAddress) {
                    var invocationData = {
                            adapter : 'myRESTAdapter',
                            procedure : 'getGmapLatLng',
                            parameters : [ pAddress ]
                        };
  
                    WL.Client.invokeProcedure(invocationData,{
                        onSuccess : mobGmapLatLngSuccess,
                        onFailure : mobGmapLatLngFailure,
                    });
                }

I also added two methods, one to handle a successful response, the other to handle a failed response.

The success handler parses the JSON response object from the HTTP adapter, and displays it to the user in an alert.

                function mobGmapLatLngSuccess(result) {
                    var httpStatusCode = result.status;
                    if (200 == httpStatusCode) {
                        var invocationResult = result.invocationResult;
                        var isSuccessful = invocationResult.isSuccessful;
                        if (true == isSuccessful) {
                            var lat = invocationResult.lat;
                            var lng = invocationResult.lng;
                            alert("Success: lat=" + lat + " lng=" + lng);
                        }
                        else {
                            alert("Error. isSuccessful=" + isSuccessful);
                        }                  
                    }
                    else {
                        alert("Error. httpStatusCode=" + httpStatusCode);
                    }
                }


The failure handler did not do much in this exercise.  A production function would obviously need more error-handling here.

                function mobGmapLatLngFailure(result){
                    alert("mobGmapLatLngFailure");
                }


After rebuilding and redeploying the app to my mobile device, I clicked the button for Valbonne, France.  The request propagated through the HTTP adapter on the Worklight Server, to the Google Geocoding Service, back to the adapter, and back to my device.  The javascript in my mobile app javascript parsed the response and popped up this simple alert:

image

As a final verification, I typed the latitude and longitude values into Google Maps.  It showed the correct location for Valbonne, France.  The other cities worked too.  Success!

image


Conclusion

This article shared the secrets of creating, testing, and using an IBM Worklight HTTP adapter with a mobile app to fetch data from a REST web service which returns the response in JSON format.

These techniques provide the foundation for writing server-side code to issue requests to multiple information sources such as web services, databases, even other apps within the same server, perhaps caching the most frequently requested information, and then returning all the data back to the mobile device in one response.

No comments:

Post a Comment

C# LINQ Joins With SQL

There are  Different Types of SQL Joins  which are used to query data from more than one database tables. In this article, you will learn a...