Understanding asynchronous callback
This chapter discusses two important concepts: Asynchronous method invocation and callbacks:
Asynchronous method invocation
This is a design pattern where an invoker method does not block while waiting for the invoked method to finish processing and return a result. Instead, the invoked method is run in a separate thread and the invoker is notified when the result is ready.
Callback function
This is a function that is passed to another function as a parameter and the callback function is called and run within this other function.
An asynchronous callback has considerations that differ from a synchronous callback. This chapter describes those considerations.
This chapter shows how to use callback functions to call an external service. This exercise uses the IBM Watson Language Translator service in IBM Cloud. You will create a Node.js module that contains the logic for these calls.
This chapter contains the following topics:
2.1 Getting started
To start, read through the objectives, prerequisites, and expected results of this use case.
2.1.1 Objectives
By the end of this chapter, you should be able to understand asynchronous callbacks and be able to write the code in a Node.js application.
2.1.2 Prerequisites
Before you start, be sure that you meet these prerequisites:
Basic knowledge of JavaScript
A workstation that has these components:
 – Internet access
 – Web browser: Google Chrome or Mozilla Firefox
 – Operating system: Linux, Mac OS, or Microsoft Windows
2.1.3 Background
In this exercise, you will use asynchronous callback functions.
A callback function is a function that is passed as a parameter to another function. The callback function is to be run only after the called function finishes running.
Example 2-1 shows an example of a callback function.
Example 2-1 Callback function example
setTimeout(function() {
console.log("A");
}, 3000);
 
setTimeout(function() {
console.log("B");
}, 2000);
 
setTimeout(function() {
console.log("C");
}, 4000);
 
setTimeout(function() {
console.log("D");
}, 1000);
The setTimeout function in Example 2-1 is a function that receives the following parameters:
A callback function that should be run after a certain time interval.
The time interval (in milliseconds) that should elapse before the callback function can run.
When calling the setTimeout function, Node.js is not waiting for the processing to finish. Instead, Node.js registers the callback function for it to be run after the response is returned.
When the code in Example 2-1 runs, the following output is returned in the console:
D
B
A
C
The result depends on the sequence of the setTimeout functions finishing their execution and not on the sequence of their declaration in the JavaScript file.
2.1.4 Expected results
This exercise shows how to use callback functions to call an external service (this exercise uses the Watson Language Translator service on IBM Cloud).
The logic of these calls will be in a Node.js module that you will create. Figure 2-1 shows a callback function to call the Language Translator service.
Figure 2-1 Expected results
The expected result of running this function is to see the translation of a word from English to Spanish using IBM Watson Language Translator service. (Figure 2-2).
Figure 2-2 Example results
2.2 Architecture
The architecture of the asynchronous callback in this chapter is shown in Figure 2-3.
Figure 2-3 Asynchronous Callback sample architecture diagram
This exercise shows how to use callback functions in your Node.js application. In this scenario, the Node.js app accesses the IBM Watson Language Translator service in IBM Cloud. The flow that is shown in Figure 2-3 is as follows:
1. The user enters the application’s URL in the web browser.
2. The web browser sends the HTTP request to the Node.js app that is deployed in IBM Cloud.
3. The Node.js app asynchronously calls the Language Translator service and registers a callback function that is to be called when the Language Translator service sends the response.
4. The Node.js app sends an HTTP request to the Language Translator service on IBM Cloud that is exposed as a REST API.
5. The Language Translator service responds to the HTTP request with the requested data (translated text).
6. The callback function (from step 3) is now run. This function responds to the HTTP request (from step 2).
7. The Node.js app sends the data to the web browser in the HTTP response.
8. The web browser displays a web page that shows the data to the user.
2.3 Step-by-step implementation
This section describes how to make asynchronous callback calls by using Node.js.
2.3.1 Log in to your IBM Cloud account
Follow these steps to log in to IBM Cloud:
1. Open your web browser, enter the following web address, and then press Enter:
2. The IBM Cloud login page opens (Figure 2-4). Click Log in and provide your account credentials.
Figure 2-4 IBM Cloud login
2.3.2 Create the Node.js application on IBM Cloud
Create the Node.js app by using the SDK for Node.js runtime on IBM Cloud:
1. In the IBM Cloud dashboard, click Create resource (Figure 2-5).
Figure 2-5 Create resource
2. The IBM Cloud Catalog page opens (Figure 2-6). It lists the infrastructure and platform resources that can be created in IBM Cloud. Scroll down to the Cloud Foundry Apps section and click SDK for Node.js.
Figure 2-6 IBM Cloud Catalog
3. In the App name field, enter vy102-XXX-nodejs. Replace XXX with any three random characters, which become your unique key (Figure 2-7). Make sure that the name of this application is different from the name of the application that you created in Chapter 1, “Developing a Hello World Node.js app on IBM Cloud” on page 1. Take note of the random characters because you will be using your unique key in the naming convention of this exercise.
The Host name field is automatically populated with the same value as the app name.
Keep the default values for the other fields.
Click Create.
Figure 2-7 Creating the Node.js app
4. The Getting started page for the created application opens (Figure 2-8). For a while, the status for vy102-XXX-nodejs is shown as Starting. Wait until the status changes to This app is awake (for IBM Cloud Lite accounts) or Running (for non-IBM Lite accounts).
Figure 2-8 Created Node.js app
2.3.3 Enable continuous delivery
Enable continuous delivery for the Node.js app by completing these steps:
1. Click Overview on the left pane, scroll down to the Continuous delivery tile, and then click Enable (Figure 2-9).
Figure 2-9 Enabling continuous delivery
A new continuous delivery toolchain tab opens (Figure 2-10).
Figure 2-10 Toolchain creation page
Scroll down to see the three main icons shown in Figure 2-11:
 – Git Repos and Issue Tracking
 – Eclipse Orion Web IDE
 – Delivery Pipeline
The Git Repos and Issue Tracking icon is selected by default.
Figure 2-11 Three primary icons: Git Repos and Issue Tracking is selected by default
2. To create the Node.js app from scratch, select New from the Repository type menu, and then click Create. A new page opens (Figure 2-12).
Figure 2-12 Create a toolchain page
2.3.4 Integrate the Node.js app with the Watson Language Translator service
An IBM Cloud service is a ready-for-use functionality that is hosted on IBM Cloud and can be accessed from your application over the internet. Examples of services are databases, message queues, and many others. In this exercise, you use the Watson Language Translator service.
Create a Language Translator service instance
In the following steps, you create an instance of the Watson Language Translator service that is hosted on IBM Cloud and access this service from your Node.js application:
1. Right-click Catalog and select Open link in new tab (Figure 2-13). A Catalog tab opens.
Figure 2-13 Open Catalog in new tab
2. In the filter field, search for the Language Translator service and click it (Figure 2-14).
Figure 2-14 Language Translator service icon
Use this service to translate text from one language to another.
3. The Language Translator service page opens (Figure 2-15). Keep the default values and click Create.
i
Figure 2-15 Creating the Language Translator service
Connect the Node.js app to the Language Translator service
To connect your Node.js app to the Language Translator service, complete these steps:
1. Click Connections on the left navigation bar, then click Create Connection.
2. From the list, select your Node.js application that you created in 2.3.2, “Create the Node.js application on IBM Cloud” on page 31, and click Connect.
3. A message prompts you to restage the application so that it can use the Language Translator service (Figure 2-16). Click Restage.
Figure 2-16 Restage after connecting to the Language Translator service
Obtain the Language Translator service credentials
The service credentials are required to access the service. To create and obtain the credentials for your Language Translator service instance, complete these steps:
1. In the Language Translator Service Details page, click Service credentials on the left navigation bar, then click New Credential (Figure 2-17).
Figure 2-17 Service Credentials
2. The Add new credential window opens. Click Add.
3. Click View credentials to display the credentials. Figure 2-18 shows a JSON object that contains the service credentials. Click the Copy icon to copy the service credentials and paste them in a text editor. These credentials are needed to access the Language Translator service instance.
Figure 2-18 Language Translator service credentials
4. Close the Service Details browser tab.
Understand the Language Translator REST API
The Language Translator service provides REST APIs, which can be called by the applications linked to it. The following steps walk you through a demo showing you how the Language Translator REST API works:
1. Open a new web browser tab. Use the following web address to open the Language Translator for IBM Watson Developer Cloud API:
2. Scroll down to the Translate Text section. Select English for the input language, and Spanish for the Output language. Then, write Hello in the Text input field and press Enter. The Text output field shows the translation as Hola as shown in Figure 2-19.
Figure 2-19 Language Translator For IBM Cloud API
3. In the Output section, click JSON. The JSON object retrieved from the API call is shown (Example 2-2).
Example 2-2 JSON object as response
{
{
"translations": [
{
"translation": "Hola"
}
],
"word_count": 1,
"character_count": 5
}
 
Note: The translations.translation field contains the translated text result. You will learn how to read the content of this field in a Node.js app in the next section, 2.3.5, “Access the Language Translator service from the Node.js app”.
4. Close the opened tab of the web browser.
2.3.5 Access the Language Translator service from the Node.js app
This section describes the steps to access the Language Translator service from a Node.js application.
1. On the View toolchain page, click the Eclipse Orion Web IDE icon.
The browser shows the generated Node.js project in the Eclipse Orion Web IDE (Figure 2-20).
Figure 2-20 Eclipse Orion Web IDE
2. Right-click the root of the project (named vy102-XXX-nodejs), and select New  File. A text field is displayed. Type manifest.yml and then press Enter. The manifest.yml file is now created.
3. Add the code snippet from Example 2-3 to the manifest.yml file. Replace the XXX with your unique key (three random characters).
Example 2-3 Code snippet: manifest.yml file
applications:
- path: .
memory: 256M
instances: 1
domain: mybluemix.net
name: vy102-XXX-nodejs
host: vy102-XXX-nodejs
disk_quota: 1024M
4. If required, change the domain on based on your IBM Cloud region as listed in Table 2-1.
Table 2-1 IBM Cloud regions and domains
Region
Domain
US South
mybluemix.net
United Kingdom
eu-gb.mybluemix.net
Sydney
syd.mybluemix.net
Germany
eu-de.mybluemix.net
5. Create a file and name it package.json. Insert the code snippet from Example 2-4 into the package.json file.
Notice the dependencies section, which includes the ready made packages to be used by the application. The package used in this exercise is watson-developer-cloud, which is the Node library used to access the Watson Developer Cloud services. You will use it in the exercise to access the Language Translator service.
Example 2-4 Code snippet: package.json file
{
"name": "NodejsStarterApp",
"version": "0.0.1",
"description": "App for understanding Callback",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"watson-developer-cloud": "^1.0.0"
}
}
6. Create a file and name it app.js. In the app.js file, insert the code from Example 2-5.
Example 2-5 Code snippet: Create http instance
const http = require('http');
The http module is used for HTTP functions.
7. Next, insert the code shown in Example 2-6.
Example 2-6 Code snippet: Create watson-developer-cloud instance
const watson = require('watson-developer-cloud');
This line imports the watson-developer-cloud package. This package allows access to all of the Watson APIs, one of which is the Language Translator service that you use in this exercise.
8. Next, insert the code snippet from Example 2-7.
Example 2-7 Code snippet: Create server to receive http request
var portNumber = process.env.VCAP_APP_PORT || 8080;
const server = http.createServer(handleRequests);
server.listen(portNumber, function() {
console.log('Server is up!');
});
This code creates a server to receive the http requests from the user. The function handleRequests is called whenever a request is received.
9. The next step is to implement the handleRequests function. Insert the code snippet from Example 2-8 at the end of the app.js file.
Example 2-8 Code snippet: handleRequests function
function handleRequests(userRequest, userResponse) {
 
}
The handleRequests function has two parameters:
 – The request (named userRequest in this example).
 – The response (named userResponse in this example).
Figure 2-21 shows the app.js file up to this point in the exercise.
Figure 2-21 Watson developer cloud library, server, and handleRequests function
In the handleRequests function, add the following line for setting the header data:
userResponse.writeHead(200, {'Content-Type': 'text/plain'});
10. Below the userResponse.writeHead line, enter the code snippet from Example 2-9.
Example 2-9 Code snippet: Identify translation request message
var helloText = 'Hello';
var fromLanguage = 'en';
var toLanguage = 'es';
These variables contain the data to be sent in the request to the Language Translator service:
 – helloText stores the text that will be translated.
 – fromLanguage stores the source language for the translation.
 – toLanguage stores the target language for the translation.
11. After the variables declaration in the function handleRequests, enter the code snippet from Example 2-10.
Example 2-10 Code snippet: Language Translator object
var language_translator = watson.language_translator({
version: 'v2'
});
The watson module includes the language_translator API. This function expects a JSON object containing details about the connection to the Language Translator service such as the URL, username, and password.
However, because the Language Translator service is bound to the Node.js app through IBM Cloud, there is no need to specify these details as they are stored in VCAP_SERVICES. Only the version of the Language Translator service is specified here.
12. Enter the code snippet from Example 2-11.
Example 2-11 Code snippet: language_translator.translate
language_translator.translate({
text: helloText,
source: fromLanguage,
target: toLanguage
}, callback);
The language_translator.translate function is called. The translate function expects two arguments:
 – A JSON object. This JSON object contains the text, source, and target fields. As shown Example 2-11, the variables helloText, fromLanguage, and toLanguage are used for setting the values.
 – A callback function. This function will be run after the Language Translator service finishes processing the request and returns the response to the Node.js app. While the Language Translator service is processing the request, the Node.js app registers the callback function so it can be run after the response is returned.
13. Before the line language_translator.translate, enter the code snippet in Example 2-12.
Example 2-12 Code snippet: language_translator callback function
var callback = function(err, data) {
if (err) {
console.log(err);
userResponse.end('Error: ' + err);
} else {
console.log(data);
userResponse.end('Translation of ' + helloText + " is " + data.translations[0].translation);
}
 
};
The callback function has two arguments:
 – The err object, which is used if an error occurs in the function
 – The data object, which contains the data returned by the Language Translator service.
The translation data can be sent in the userResponse object, which is the response object that contains the text to be returned to the web browser.
The handleRequests function should now look as shown in Example 2-13.
Example 2-13 Code snippet: handleRequests function complete
const http = require('http');
const watson = require('watson-developer-cloud');
 
 
var portNumber = process.env.VCAP_APP_PORT || 8080;
const server = http.createServer(handleRequests);
server.listen(portNumber, function() {
console.log('Server is up!');
});
 
 
function handleRequests(userRequest, userResponse) {
 
userResponse.writeHead(200, {
'Content-Type': 'text/plain'
});
 
var helloText = 'Hello';
var fromLanguage = 'en';
var toLanguage = 'es';
var language_translator = watson.language_translator({
version: 'v2'
});
 
var callback = function(err, data) {
if (err) {
console.log(err);
userResponse.end('Error: ' + err);
} else {
console.log(data);
userResponse.end('Translation of ' + helloText + " is " + data.translations[0].translation);
}
 
};
 
language_translator.translate({
text: helloText,
source: fromLanguage,
target: toLanguage
}, callback);
 
}
14. If you see a warning message Parameter 'userRequest' is never used for the line function handleRequests(userRequest, userResponse), click Disable no-unused-params.
15. Next, click Create new launch configuration and the “+” sign in the drop-down list. If you do not have the Create new launch configuration option, skip this step.
In the Edit Launch Configuration window, ensure that the Organization is set to your email address, and Space is set to dev, and click Save.
16. Click the play icon (Deploy the App from the Workspace) to deploy the app.
17. After the deployment is complete, click the Open the deployed app icon.
You see the output in your browser (Figure 2-22). The output shows the translation of the Hello text from English to Spanish.
Figure 2-22 Language Translator output
2.3.6 Access the Language Translator service through a Node.js module
In 1.3.6, “Add a module to the Node.js application” on page 21, you learned how to create a Node.js module. In this section, you will learn how to return a callback function in a module.
The following steps create a Node.js module, called translator, that will contain the logic for accessing the Language Translator service:
1. In the root path, create a new folder and name it translator.
2. In the translator folder, create a file named package.json.
3. Enter the code snippet in Example 2-14 in the package.json file. The main field contains the path of the JS file that has the Language Translator service code.
Example 2-14 Code snippet: package.json for Language Translator
{
"name": "translator",
"main": "./lib/translator",
"dependencies": {
"watson-developer-cloud": "^1.0.0"
}
}
The package.json file in Example 2-14 represents the translator module.
4. In the translator folder, create a new folder named lib.
5. In the lib folder, create the translator.js file.
The translator folder (and translator.js file) now look like Figure 2-23.
Figure 2-23 The translator.js file
Leave the translator.js file empty for now.
6. Open the app.js file and remove all code in this file.
7. Add the code in Example 2-15 to the app.js file.
Example 2-15 Code snippet: Importing http and translator
const http = require('http');
const translatorModule = require('./translator');
The first line is for importing the http module. The second line is for importing the translator module that you created in the previous steps. You now import the translator module into the app.js file. You implement the translator module later.
8. Add the code snippet from Example 2-16 to the app.js file.
Example 2-16 Code snippet: Declare text, from and to fields
var helloText = 'Hello';
var fromLanguage = 'en';
var toLanguage = 'es';
These lines declare the variables for the input fields that you use when accessing the Language Translator service.
9. Below the var toLanguage line, add the code snippet from Example 2-17.
Example 2-17 Code snippet: Create server and listen on a port
var portNumber = process.env.VCAP_APP_PORT || 8080;
const server = http.createServer(handleRequests);
server.listen(portNumber, function() {
console.log('Server is up!');
});
These lines create the server and listen on a certain port.
createServer receives the handleRequests callback function. You implement this function in the next step.
10. Add the code snippet from Example 2-18 for the handleRequests callback function.
Example 2-18 Code snippet: handleRequests
function handleRequests(userRequest, userResponse) {
userResponse.writeHead(200, {
'Content-Type': 'text/plain'
});
}
The body has code that sets the header content.
11. Inside the handleRequests callback function, after the userResponse.writeHead(200, { 'Content-Type': 'text/plain' }); function call, enter the code snippet from Example 2-19.
Example 2-19 Code snippet: getTranslation
translatorModule.getTranslation(helloText, fromLanguage, toLanguage, callback);
The code line in Example 2-19 calls the getTranslation function that should be defined in the Language Translator module.
This function has following parameters:
 – helloText
 – fromLanguage
 – toLanguage
 – callback function, which will be called after the getTranslation function finishes its execution
12. Before the translatorModule.getTranslation() line you just added, insert the code snippet from Example 2-20 for the callback function that is mentioned in the previous step.
Example 2-20 Code snippet: The callback function with translatorOutput
var callback = function(error, translatorOutput) {
if (error) {
userResponse.end(error);
} else {
userResponse.end('Translation of ' + helloText + " is " + translatorOutput);
}
 
};
The callback function is expected to have an error parameter that holds a value in case of errors. The other parameter is for the translatorOutput. If the error object is not null, the HTTP response is sent back to the user with this error. If no error occurs, the message containing the translatorOutput is sent in the HTTP response back to the user.
The app.js file now looks like the file in Figure 2-24.
Figure 2-24 The app.js file using the translator module
Save the file by clicking File  Save.
13. Open the translator.js file. Add the code snippet from Example 2-21 to import the watson-developer-cloud module.
Example 2-21 Code snippet: Importing the watson-developer-cloud API
var watson = require('watson-developer-cloud');
14. Next, define and export the getTranslation data, which is used in the app.js file. The initial code looks like the code snippet shown in Example 2-22.
Example 2-22 Code snippet: Exporting the getTranslation function
exports.getTranslation = function getTranslation(helloText, fromLanguage, toLanguage, callback) {
 
};
This function receives the fields helloText, fromLanguage, toLanguage, and the callback function that is to be run when the getTranslation function finishes execution.
15. Inside the getTranslation function, add the code snippet from Example 2-23. This code is for accessing the Language Translator API.
Example 2-23 Code snippet: Access Language Translator API
var language_translator = watson.language_translator({
version: 'v2'
});
Below the code in Example 2-23, add the code snippet from Example 2-24 for the actual call to the Language Translator service.
Example 2-24 Code snippet: language_translator translate function
language_translator.translate({
text: helloText,
source: fromLanguage,
target: toLanguage
}, translatorCallback);
16. Before the language_translator.translate line, add the code snippet from Example 2-25. This code defines the translatorCallback callback function.
Example 2-25 Code snippet: translatorCallback function
var translatorCallback = function(err, data) {
};
The translatorCallback callback function is called after the response from the language_translator.translate function is returned.
The translatorCallback function contains two parameters:
 – err: This parameter has a value if there is an error returned when the language_translator.translate function is run.
 – data: This parameter has the returned response data from running the language_translator.translate function.
17. Inside the translatorCallback function, add the code snippet from Example 2-26.
Example 2-26 Code snippet: translatorCallback callback function details
if (err) {
console.log(err);
callback(err, null);
} else {
console.log(data);
callback(null, data.translations[0].translation);
}
The code first checks if an error occurred. In case of error, run the callback function, with the first parameter set to the err value and the second parameter, the data object, to null.
If err is null, then no errors occurred. In this case, the data object has the response data from calling the Language Translator service.
Now, the callback function can be run by setting the first parameter as null (because no errors occurred) and the second parameter as data.translations[0].translation to read the returned translation from the data JSON object. The JSON object structure is shown in Example 2-2 on page 40.
Figure 2-25 shows the translator.js file at this point.
Figure 2-25 Translator module code
18. Click the play icon (Deploy the App from the Workspace) to deploy the app. Confirm if you are prompted to restart the app. After the deployment is complete, click the Open the Deployed App icon.
The window showing the translation is displayed (Figure 2-26).
Figure 2-26 Results of translator output
2.3.7 Stop the application
IBM Cloud Lite account provides you with 256 MB of application memory for Cloud Foundry apps and 100 Cloud Foundry Services.
To free the resources that are assigned to your application, you can either stop your application or delete it. To do so, complete these steps:
1. Stop your application by clicking the Stop the App icon(Figure 2-27).
Figure 2-27 Stop the application
2. Close your web browser.
2.4 Exercise review
In this exercise you accomplished the following goals:
Created the Language Translator service in IBM Cloud and connected it to your Node.js app.
Used asynchronous callback functions in your Node.js app and learned how the callback function is run.
Created a module in Node.js to call the Language Translator service and used it from other JS files.
 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.64.66