Integrating the Bluemix Watson Translation service into an XPages application

In this article I will demonstrate how to integrate the Bluemix Watson Translation service into a functioning XPages application.

Bluemix Watson Translation Service

Following on from one from my previous posts on the subject I have been looking for a good workable example of using a Bluemix service within an XPages application. As I said before this is as much an exercise in me learning more about node.js and Bluemix as anything else – but I also love being able to share.

Based on the previous post about how to get the Watson Q and A service up and running it took me 12 minutes to get a working example of the Watson Translation service up and running on a Bluemix site. Just for disclaimers I have no idea how good the Watson service is and I am not advocating it – this is purely an exercise in being able to use a Bluemix service, more so that what it does.

So I followed the steps in my previous blog but applied them to the example post on the Watson Translation service. This was pretty simple and once again the only thing to change was the manifest.yml file to name the service and application correctly.

w2

http://xominowatsontranslate.mybluemix.net/

When you type into the TEXTAREA box (1) and then hit “Translate”(2) the result is displayed in the Output (3)

The page does a full refresh and the answer is displayed. The node.js code running behind the application is fairly self explanatory :

  • (looking at the code snippet below) we can see the values POST’d from the application are received on the node.js server in the app.POST
  • The posted field values are turned into a separate request to the Watson translation service
  • The Watson request (watson_req) is sent as a serversiude request to the Watson service
  • The results from that are sent back to the response object “watson_res”
  • The node.js response (res) back to the user is then set back to the browser using the jade template (index)
    • return res.render(‘index’,request_data);

// Handle the form POST containing the text and sid, reply with the language
app.post('/', function(req, res){

    var request_data = {
        'txt': req.body.text,
        'sid': req.body.sid,
        'rt':'text' // return type e.g. json, text or xml
    };

    var parts = url.parse(service_url);
    // create the request options to POST our question to Watson
    var options = { host: parts.hostname,
        port: parts.port,
        path: parts.pathname,
        method: 'POST',
        headers: {
            'Content-Type'  :'application/x-www-form-urlencoded', // only content type supported
            'X-synctimeout' : '30',
            'Authorization' :  auth }
    };

    // Create a request to POST to Watson
    var watson_req = https.request(options, function(result) {
        result.setEncoding('utf-8');
        var responseString = '';

        result.on("data", function(chunk) {
            responseString += chunk;
        });

        result.on('end', function() { //this is triggered when the response from Watson is completed
            // add the response to the request so we can show the text and the response in the template
            request_data.translation = responseString;
            console.log('request',request_data);
            return res.render('index',request_data); //<------response sent back to the web page
        })

    });

    watson_req.on('error', function(e) {
        return res.render('index', {'error': e.message})
    });

    // create the request to Watson
    watson_req.write(querystring.stringify(request_data));
    watson_req.end();

});

 

You can see that in action through firebug – here is the POST parameters

w3and here is the response – the new HTML containing the answer

w4

 

Modifying the service

Here is the thought process which occurred to me:

  • Well that is cool but if I want to integrate this into an XPage then I will need to return the result as JSON and not a whole HTML page
  • But I do not want to break the example so how can I do that ?
  • I can use a new route – so if I POST at a different URL, the node.js server can be made to be smart enough to do something different
  • Ah…….and then I will have CORS issues because my application will be running at xomino.com and the bluemix app is not

Replicating the POST as code

So the first thing I did was try and replicate the code in jQuery (as I know best) so that I could mimic a POST event in ajax without using a form. In the following example you can see I added jQuery to my page (jQuerify plugin for firebug). I then simulated an AJAX POST to the translation service (emulating the form post).

w5

 

The response is the HTML of the new page, so I know this is at least the right AJAX code.

w6

 

But when I am on the copper.xomino.com site and I try and repeat the same thing, as expected CORS issues.

w7

Ryan Baxter (who frankly has been a huge support and help in learning all this) said to me

“You are in luck, CORS is dead simple with Node  – https://www.npmjs.org/package/cors” and how right he was.

Adding the CORS package to my Bluemix application

The way you add a package to your Bluemix application is by updating the package.json file. This file contains all the npm modules that will be needed and what is even cooler is that these will be npm installed within your node server automagically on deployment

w8

So then I need to add the cors enabled page to my application. But I did not want to change the core example on the site. So what I did was create a new “route” within the node.js application and told it to do something different….

Originally we had this within the example


// Handle the form POST containing the text and sid, reply with the language
//the route in this case is "/" - so basically the root of the application
app.post('/', function(req, res){
	//stuff
}

and to create a new route we just add a different app.post


// Handle the form POST containing the text and sid, reply with the language
var cors = require('cors'); //add the cors module code to the application
app.use(cors());
var corsOptions = {
    origin: 'http://copper.xomino.com' //allow copper to be a site which can work with the watson site
};

//note the new cors(corsOptions) parameter in the app.post function
app.post('/xpages', cors(corsOptions), function(req, res){ //when a user posts to  site.com/xpages do this code instead of the default '/'
	//stuff
}

What I then changed was the response code – this was the original code responding with text and rendering using the jade index.jade template

	//......
        result.on('end', function() {
            // add the response to the request so we can show the text and the response in the template
            request_data.translation = responseString;
            console.log('request',request_data);
            return res.render('index',request_data); //render the response using the index,jade template and passing the request_data
        })

Instead of res.render I used res.json to send the request_data object back to the browser directly.

	//......
        result.on('end', function() {
            // add the response to the request so we can show the text and the response in the template
            request_data.translation = responseString;
            console.log('request',request_data);
            return res.json(request_data);
        })

So in this way I left the default page alone (“/” server root) – the example still works – but I added a new route (“/xpages”) so that my XPage application could POST at it.

I committed the code and pushed back up to Jazz Hub, restarting the service as we went…….and low and behold success…..

w9

As you can see from the above image, I am at the copper.xomino.com website. Using the slightly modified code to now post at

I get a response from the Bluemix website with the JSON from the Translation service. You can see from the headers the CORS header is added for copper.xomino.com

w10

Note – if you go to http://xominowatsontranslate.mybluemix.net/xpages you will GET an error. This is because my node application does not have an app.get for the /xpages route

So then XPages….

Integrating the Watson Transation service into an XPage application

Once I have the working ajax code it is very simple to add it to an XPage and just pick up the field values on the fly….. I cheated to some extent and copied and pasted the HTML from the original example into my XPage….hey why not this is an example after all…

I added a couple of classes to the example so that I could easily pick out the field values…

a1

And then the jQuery code to add to the application. In this code I

  • Select the .translate class (the translate button)
  • In the click event I get the data from the form
    • the .sid select box for the language translation
    • The text value from the textbox (.theOriginal) field
  • I then submit to the the translation service as before
  • In the .done() of the AJAX request, the incoming msg.translation is then added to the .theTranslation field

a2


 The demo

As you can see from the video – I am able to:

  • type in any value
  • send it to the bluemix service
  • receive the answer and display it on the screen
  • save the original and translated values as notes documents within my XPages application
  • Firebug shows the fact that the POSTS are going to http://xominowatsontranslate.mybluemix.net/xpages

Conclusion

I think this is a great example of using a “service” on another website to be able to enhance the functionality in your own XPages application. If IBM are successful in their investigation to put Domino inside of Bluemix, this capability will all happen behind the scenes and could be easily written as one true application……bring it on…🙂

 

PS

This exercise was particularly gratifying because it feels like a culmination of all the work I have done in XPages over the last 3 years.

  • Without the jQuery and Firebug work I did at the start of XPages development, prototyping this would have been much more tedious.
  • Learning XPages has forced me to have a better understanding of AJAX and jQuery
  • If it were not for Angular and the “Write once run anywhere” I did for MWLUG, I would not have learned about CORS.
  • If it was not for the Angular work I would not understand “routes” within an application
  • …..and now I am learning about node.js and Bluemix PaaS

Keep learning !

 

 

2 thoughts on “Integrating the Bluemix Watson Translation service into an XPages application

  1. The idea of describing a tutorial of Bluemix Watson Translation is good. Each and every step is described very well with screen shorts. Thanks for sharing this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s