Oracle by Example brandingCreate Custom Components to Integrate with Backend Services

section 0Before You Begin

This 45-minute tutorial shows how to create a custom component that integrates currency conversion functionality into a skill conversation. You'll learn:

  • How to start a new custom component service project using the Oracle Bots Node.js SDK.
  • How to define the custom component's name, input parameters, and returned actions.
  • How to implement logging.
  • How to invoke a remote REST service.
  • How to deploy custom component services to a Node container that's embedded in your Oracle Digital Assistant instance.

Background

Custom components are reusable units of custom code that you can call from your skill's dialog flow. From a skill-design perspective, there's no difference between a custom component that you build and the system components provided by Oracle Digital Assistant.

The most common use case for building custom components is to integrate a skill conversation with a remote backend system. You develop custom components using JavaScript and Node.js.

What Do You Need?

This tutorial is for developers who are familiar with JavaScript and Node.js development. To complete this tutorial:

  • You need access to an Oracle Digital Assistant instance.
  • You need a JavaScript IDE installed. For example, this tutorial uses Microsoft Visual Studio Code in its screenshots. If you feel comfortable using a text editor, then that is fine too.
  • You must have Node.js and Node Package Manager (NPM) installed for global access. If you used a Node installer (Windows, Mac), then both the node and npm executables should be available to you. To test if you have Node.js and NPM installed, open a terminal window and try the following commands separately:

    $ node -v

    $ npm -v


section 1Install the Oracle Bots Node.js SDK

The Oracle Bots Node.js SDK is a Node module for building and deploying custom component services for Oracle Digital Assistant. You can learn about the Oracle Bots Node.js SDK at GitHub and the Node Package Manager website.

Follow these steps to install the Oracle Node.js Bots SDK to your local machine.

  1. Open a terminal window.
  2. If your Internet access is through a proxy, you might need to do the following to be able to install the Oracle Bots Node.js SDK from the Internet:

    • To get the external IP address of your proxy, open a browser and go to http://www.whatismyproxy.com/.
    • In the terminal window, enter these commands:
        $ npm config set proxy http://<external_ip>:80
      $ npm config set https-proxy http://<external_ip>:80
  3. To install Oracle Bots Node.js SDK for global access on your laptop, enter this command:
    $ npm install -g @oracle/bots-node-sdk
    On a Mac, you use the sudo command:
    $ sudo npm install -g @oracle/bots-node-sdk
  4. To verify the success of your installation, enter this command:
    $ bots-node-sdk -v
    Version: 2.2.2
    $
    The command should print the Oracle Bots Node.js SDK version.

section 2Request a fixer.io Currency Converter API Key

The Fixer website at fixer.io offers current and historic exchange rates for up to 170 currencies. To complete this tutorial, you need a free subscription that allows you to get current conversion rates.

  1. Go to https://fixer.io.
  2. Click GET FREE API KEY in the upper right corner.
    GET FREE API KEY button
  3. In the Pricing section, click GET FREE API KEY.
    GET FREE API KEYFREE pricing plan icon
  4. Complete the registration form.
  5. Copy and save the free API key that's displayed in the confirmation page.
    Fixer IO Confirmation page

The free API key has restrictions. For example, the conversion rates are updated less frequently and you only can make requests using HTTP (not HTTPS). In addition, the base currency is Euro (EUR). You can handle the base currency restriction in your custom component code and enable users to specify different base currencies.


section 3Create the Custom Component Service

To create a custom component service project, use the Oracle Bots Node.js SDK command line interface (CLI) that was installed when you installed the Oracle Bots Node.js SDK. The Oracle Bots Node.js SDK provides all the infrastructure and tools that you need to test, debug, and deploy custom component services.

Create a Custom Component Package

In this section, you use the bots-node-sdk init command to create a package structure with the necessary files, including a custom component JavaScript file for the the currency converter component. This command also installs all the dependencies.

  1. Open a terminal window and navigate to the folder that will contain your component package. Ensure that the folder's path doesn't contain spaces. For example, on Windows, don't navigate to a folder under Program Files.
  2. Enter this command:

    $ bots-node-sdk init converterccs --component-name CurrencyConverter

    This command might take several minutes to complete.

    As shown in this screenshot, the command creates a subfolder named converterccs, which contains your main.js and package.json files, along with the installed dependencies in node_modules. It also creates a components folder that contains CurrencyConverter.js, which is the file that you'll modify.

    project structure

  3. (Optional) Open the package.js file and change the name from my-custom-component to convertercss.

Provide the Custom Component Framework

The custom component service that you just created is the equivalent to the hello world example. In the next steps, you'll modify the code to become the starter for the currency-converter custom component.

  1. Open your JavaScript editor of choice.
  2. In the JavaScript editor, open the converterccs/components/CurrencyConverter.js file.

    Alternatively, if your editor supports projects, you can open the converterccs folder as a project.

  3. In the Explorer, expand the components node and open CurrencyConverter.js.
    JS editor with opened component file
  4. Line 5 defines the component's name. To avoid possible naming conflicts when a skill uses more than one component service, add a prefix to the component name. Change:
    name: 'CurrencyConverter',
    to:
    name: 'complete.training.CurrencyConverter',

    Tip: You can click Copy in the code box to copy its contents.

  5. Now you'll define the input properties that the skill can pass to the custom component. Replace line 7, which defines the human property, with the following code:
          variable: {required: true,type: 'string'},
          baseCurrency: {required: true,type: 'string'},
          targetCurrencies: {required: true,type: 'string'},
          amount: {required: true,type: 'int'}

    The skill uses the variable property to name the dialog-flow context variable that the custom component can use to return the result object. The baseCurrency defines the currency of the amount that's to be converted, and the targetCurrencies lists the currencies that the amount must be converted to. The last property defines the amount to convert.

  6. Change this code line:
    supportedActions: ['weekday', 'weekend']
    to:
    supportedActions: ['success', 'failure']

    The custom component will use these actions to indicate to the skill whether the currency conversion succeeded.

    With these changes, the metadata() function should like this, with the function starting on line 4 and ending on line 13:

     4  metadata: () => ({
     5    name: 'complete.training.CurrencyConverter',
     6    properties: {
     7      variable: {required: true,type: 'string'},
     8      baseCurrency: {required: true,type: 'string'},
     9      targetCurrencies: {required: true,type: 'string'},
    10      amount: {required: true,type: 'int'}
    11    },
    12    supportedActions: ['success', 'failure']
    13  }),
  7. Change the invoke: (conversation, done) function to the following code:

      invoke: (conversation, done) => {
    
        const { variable } = conversation.properties();
        const { baseCurrency } = conversation.properties();
        const { targetCurrencies } = conversation.properties();
        const { amount } = conversation.properties();
    
        done();
      }

    Your code should look like this, with the invoke() function starting on line 14 and ending on line 22:
    14  invoke: (conversation, done) => {
    15
    16    const {variable} = conversation.properties();
    17    const {baseCurrency} = conversation.properties();
    18    const {targetCurrencies} = conversation.properties();
    19    const {amount} = conversation.properties();
    20
    21    done();
    22  };
    

    Each of the lines that begin with const reads the value for a required component input parameter. Because the input parameters are flagged as required in the metadata() definition, the code doesn't have to check for missing values (the skill will invoke a runtime exception if a required property is missing). If a property is optional, then your code should check for null values.

    The done() function call invokes a callback that passes the component response back to the Oracle Digital Assistant skill that invoked the custom component.

Add Your First Logging Statement

The Oracle Bots Node SDK exposes a configurable logger. By default, logging is set up to use the console logger. You'll use the logger to track the custom component processing.

  1. Locate the the blank line above the call to done(), which should be line 20.
  2. Replace the blank line with the following code in a single line:
    conversation.logger().info("Input parameter values: variable: "+variable+", baseCurrency: "+baseCurrency+", targetCurrencies: "+targetCurrencies+", amount: "+amount);

    This log statement prints the names and values of the component's input parameters.

Note: Because this entry-level tutorial doesn't cover custom component debugging, you are using the logger to track the processing.

Build the fixer.io Request URL

  1. Create a new line under conversation.logger().
  2. Add the following code, including the blank line before the first var statement.
    
        var tmpTargetCurrencies = targetCurrencies+","+baseCurrency;
        var fixerIoAPIKey = "<replace with your api key>"
        var reqUrl = "http://data.fixer.io/api/latest?access_key="+fixerIoAPIKey + "&base=EUR&symbols=" + tmpTargetCurrencies;
        // hide API key from logs
        conversation.logger().info("fixer.io request URL:"+reqUrl.replace(fixerIoAPIKey,"*********"));
    The custom component's invoke function should now look like this, with the invoke function starting on line 14 and ending on line 29:
    14  invoke: (conversation, done) => {
    15
    16    const {variable} = conversation.properties();
    17    const {baseCurrency} = conversation.properties();
    18    const {targetCurrencies} = conversation.properties();
    19    const {amount} = conversation.properties();
    20    conversation.logger().info("Input parameter values: variable: " + variable + ", baseCurrency: " + baseCurrency + ", targetCurrencies: " + targetCurrencies + ", amount: " + amount);
    21
    22    var tmpTargetCurrencies = targetCurrencies + "," + baseCurrency;
    23    var fixerIoAPIKey = "<replace with your api key>"
    24    var reqUrl = "http://data.fixer.io/api/latest?access_key="+fixerIoAPIKey + "&base=EUR&symbols=" + tmpTargetCurrencies;
    25    //hide  API key from logs
    26    conversation.logger().info("fixer.io request URL:" + reqUrl.replace(fixerIoAPIKey, "*********"));
    27
    28    done();
    29  };
  3. In line 23, which begins with var fixerIoAPIKey, replace <replace with your api key> with your fixer.io API key.

The free fixer.io subscription key only supports EUR as the base currency. To be able to use any currency as the base currency, the fixer.io request URL needs to contain the skill-provided base currency as an additional value for the target currency.

The replace(...) function in the logging statement ensures that your fixer.io API key does not show in the log message.

Add the Currency Conversion Code

This tutorial uses the Node.js Request module to access the fixer.io REST service. Because the Request module is not part of the Node.js core installation, you must first install it.

  1. Switch to the terminal window, and navigate into the converterccs folder.
  2. Enter the following npm command to install the Request Node module and add it as a dependency in the package.json file:
    $ npm install request
    npm warn converterccs@1.0.0 No repository field.
    npm warn The package @oracle/bots-node-sdk is included as both a dev and production dependency.
    
    + request@2.88.0
    added 42 packages from 52 contributors and audited 223 packages in 3.615s
    found 0 vulnerabilities
    
    converterccs $
  3. Switch to your JavaScript editor.
  4. To create a reference to the request module, add the following code into line 2 (right under the 'use strict' code line) :
    var request = require('request');
  5. Near the bottom of the file, add a new line above the done() function call.

    You should now have 2 blank lines above the done() function call.

  6. Replace the blank line that's just above the done() function call with the following code, which calls the fixer.io remote REST service:
        request(reqUrl, {json: true }, (err, res, body) => {
    
        })
    Your code should look like this:
    24     var reqUrl = "http://data.fixer.io/api/latest?access_key="+fixerIoAPIKey + "&base=EUR&symbols=" + tmpTargetCurrencies;
    25     //hide  API key from logs
    26     conversation.logger().info("fixer.io request URL:" + reqUrl.replace(fixerIoAPIKey, "*********"));
    27 
    28     request(reqUrl, {json: true}, (err, res, body) => {
    29 
    30     });
    31     done();
    32   }
    33 };
  7. Remove the done(); code line (line 31 in the above code snippet). You'll add this code to another location in the final currency conversion implementation.

    Note: Typically, because the done() function call is so important, you shouldn't remove the done() call, but instead wait until you've built the code that you can move it to so that it serves as a reminder. In this case, you'll re-add the funtion in the next section, so it's OK to delete it now.

  8. Now that you've defined the basic outline for the complete.training.CurrencyConverter component, you can implement the code to convert the base currency amount into one or more target currencies.

    Copy this code snippet.

  9. Place your cursor in line 29, which is a blank line in the body of the request() function.
  10. Replace line 29 with the code that you copied to the clipboard.
  11. Save your work.
  12. Compare your custom component with this sample code, which is also shown in the following screenshot.
    completed request function

    Let's pause for a few minutes to understand the code that you just added.

    Line Description
    28 The request() function performs the REST call to the fixer.io website. It then calls an anonymous function to which it passes the response object (res), the response body (body), and the error object (err) if it exists.
    30 A 200 response status code means that the REST service call succeeded.
    31 Even if the REST call succeeded, the response may contain an error, such as an invalid API key. This line checks the response body to see if the conversion was successful.
    35 If the request returned conversion rates, then this code block saves the rates in an array. The response body is a JSON object, so the rates are retrieved from body.rates.
    36 To work around the free API key limitation that only EUR can be used as a base currency in the request, the target currency is set to the skill-provided base currency. In this line of code, the base currency is removed from the conversion rates so that only target currencies get reported back to the skill.
    37 This line computes the converted amount for the currently handled target currency. To get the conversion rate of the target currency relative to the skill-provided base currency (and not EUR), it divides the target currency rate by the base currency rate, which is the skill-provided currency rate in relation to EUR. The code then saves the currency symbol (for example, USD), the conversion rate, and the converted amount to an object, and then adds the object to an array.
    47-48 These lines build the response object that will be returned to the skill. The result object contains a base property, which holds information about the base currency, and a conversion property, which contains all the target currencies and their converted amounts.
    54 This code saves the result object to a dialog-flow context variable. The name of the context variable was provided by the skill designer through the custom component's variable property.
    55 In this line, the custom component triggers navigation to the success transition action before calling done() to return the request to the skill.
    59 and 69 These code sections handle the cases where 1) the conversion wasn't successful, such as when the API key is missing, and 2) the response status code wasn't 200.

Note: We intentionally haven't explained the structure of the returned object. Later, when you wear the skill designer's hat, you'll learn how to get to know the structure of custom component response data.


section 4Package and Deploy the Custom Component Service

You can deploy custom components to either a skill's embedded container, a remote Node server, or Oracle Mobile Hub. In this tutorial, you'll deploy your custom component service to a skill's embedded container. For this, you first need to package the custom component service into a deployable file.

Package the Component Project for Deployment

  1. Save your work in your JavaScript IDE.
  2. Open a terminal window and navigate into the converterccs folder.
  3. In the convertercss folder, enter following npm command.
    $ npm pack
    converterccs $ npm pack
    
    > convertercss@1.0.0 prepack /converterccs
    > npm run bots-node-sdk -- pack --dry-run
    
    
    > convertercss@1.0.0 bots-node-sdk /converterccs
    > bots-node-sdk "pack" "--dry-run"
    
    ---------------------------------------------------------------------
    Component Package 'converterccs' is valid!
    ---------------------------------------------------------------------
    npm notice
    npm notice package: convertercss@1.0.0
    npm notice === Tarball Contents ===
    npm notice 549B  package.json
    npm notice 60B   main.js
    npm notice 2.3kB README.md
    npm notice 3.0kB components/CurrencyConverter.js
    npm notice === Bundled Dependencies ===
    npm notice request
    npm notice === Tarball Details ===
    npm notice name:          convertercss
    npm notice version:       1.0.0
    npm notice filename:      convertercss-1.0.0.tgz
    npm notice package size:  1.0 MB
    npm notice unpacked size: 4.0 MB
    npm notice shasum:        0e189b9547cc91c2b2a458069bf3583c2862ee7e
    npm notice integrity:     sha512-I+31z5hgTvhoZ[...]U+qo6eSveJDNQ==
    npm notice bundled deps:  1
    npm notice bundled files: 592
    npm notice own files:     4
    npm notice total files:   596
    npm notice
    convertercss-1.0.0.tgz
    converterccs $

    Because of the prepack script in the package.json file, the command first executes this command to verify the package. The command then packages the Node project and its dependencies into a deployable tarball, converterccs-1.0.0.tgz.

    Note: Your tarball must include all dependencies except for devDependencies.

Clone the Tester Skill

If you are using a shared Oracle Digital Assistant instance, then the test skill might already exist. If it does, then you can simply clone the skill. If it doesn't exist, then skip to the next section, where you import the skill.

  1. To open the Oracle Digital Assistant instance, open a browser and go to <your-instance url>/botsui.
  2. Click icon to open side menu on the top-left corner of the page to expand the side menu.
  3. Expand Development and select Skills.
    Main Menu
  4. Click icon to open side menu again to hide the side menu.
  5. In the Skills dashboard, type currency in the Filter field to find the CurrencyConverterTester skill.

    If the CurrencyConverterTester skill isn’t available in your instance, then skip to the next section to import it.

  6. On the CurrencyConverterTester card, click Options Options, and then select Clone.
  7. Name the skill <your-initials>_CurrencyConverterTester, or use any prefix that creates a name that's unique to the instance. For example, FN_CurrencyConverterTester.
  8. Enter a short description.
  9. Select Open cloned skill afterwards, and then click Clone.

Import the Tester Skill

If your instance doesn't have the CurrencyConverterTester skill, then you can import the one that we provide.

  1. Download currency-converter-tester-1-0.zip to your local machine.
  2. To open the Oracle Digital Assistant instance, open a browser and go to <your-instance-url>/botsui.
  3. Click icon to open side menu on the top-left corner of the page to expand the side menu.
  4. Expand Development and select Skills.
    Main Menu
  5. Click icon to open side menu again to hide the side menu.
  6. Click import skill button to start the import process.
  7. Browse to the folder where you saved the dowloaded currency-converter-tester-1-0.zip file, select it, and then click Open to upload and install the starter skill.
  8. Locate your CurrencyConverterTester skill and click it's tile to open it.

    If you don't see the skill, type currency in the Filter field to find it.

Deploy Your Custom Component Service to the Skill

  1. In the CurrencyConverterTester skill, click Components Components icon to open the component service page.
  2. Click + Service button to open the Create Service dialog.
  3. In the Name field, enter CurrencyConverter.
  4. In the Description field, enter fixer.io integration.
  5. Ensure that Embedded Container is selected.
  6. Locate the converterccs-1.0.0.tgz file in the converterccs folder on your file system.
  7. Drag-and-drop the converterccs-1.0.0.tgz file into the Create Service dialog's Package File field.
  8. Click Create.
    Component registration
  9. Wait for the Status field to show Ready, which may take a few seconds.
    Status showing deployment as ready
  10. Expand CurrencyConverter if it isn't already expanded, and select complete.training.CurrencyConverter. Notice that the component description is the information that you defined in the custom component's metadata() function:

    Component description

    With the custom component service deployed to the skill's embedded container, you are ready to test the component.


section 5Test the Custom Component

The tester skill's dialog flow is aleady set up for testing. If you closely followed the steps in this tutorial, then the component name, the input parameter names, and the action transition names match the names used in the converter: state in the dialog flow. If you deviated from the tutorial, you must first apply the changes to the converter: state in the flow.

Note: The tester flow uses a composite bag entity to guide users through the steps of providing a base currency, a conversion amount, and one or many target currencies. Although the currency converter that you built supports 170 currencies, the skill uses a reduced list. If you want to learn more about composite bag entities, try the Enable Real-World Entity Extraction with Composite Bag Entities tutorial.

  1. Click Flows Flows to open the dialog flow editor.

    Notice the getConversion: state in line 15. The System.ResolveEntities component accesses the CONVERSION composite bag entity through the conversion context variable, which is referenced from the component's variable property. The System.ResolveEntities resolves the composite bag entity, asking the user to provide a base currency, a currency amount, and one or more target currencies.

    Note: This tutorial doesn't make use of the composite bag entity's out-of-order extraction functionality. Users will have to provide one-by-one each piece information that's required to perform the currency conversion.

    The converter: state in line 23 references the custom component that you built. The custom component input parameters reference the conversion variable to obtain their values. The custom component saves the conversion results in the conversionResult context variable.

  2. To test the skill, click Skill Tester Skill Tester, which is located near the bottom of the left navigation bar.
  3. Start by entering hi.
  4. From the displayed currency list, select CAD for the base currency.
  5. Enter 100 for the amount to convert.
  6. When asked for the target currencies, type 4 5 9, and then press the Enter key.
    Converter testing

    As a result, you should see this skill response, which provides the currency amount and rate for each target currency:

    Conversion response
  7. Click Reset to reset the tester.
  8. Enter hi.
  9. Select USD as the base currency. You'll have to click Show More twice for the USD symbol to show.
  10. Enter 100.
  11. Type EUR CHF GBP, and then press the Enter key. You should get a conversion quote similar to the one before.

    Note: The custom component was designed to not display any target currency that matches the base currency.

  12. Reset the tester and continue trying different conversions.
  13. Close the tester, but don't reset it. You'll need the log messages from the current session for the next section of the tutorial.

section 4View The Component's Log Messages

The custom component prints log messages from within its code (conversation.logger().info(...). You can view these messages from the component service page.

  1. Click Components Components icon to open the component service page.
  2. Select CurrencyConverter, click Diagnostics, and then click View Logs.
    Log Viewer

    The dialog displays log messages that are similar to those shown in the following screenshot, such as:

    [2019-03-28T17:27:27.889] [INFO] service - Successful conversion
    Logs written by converter

    Notice the following log message:
    access_key=*********&base=EUR&symbols=CHF,CNY,INR,CAD
    Instead of printing the access credential, the custom component code masks the information, so that it's not disclosed. This masking is part of the custom component code that you edited.


section 4Use the Skill Tester to Discover the Response Data Structure

This tutorial didn't explain the custom component response data structure when you created the custom component or explored the content of the dialog flow. How do you know what is in a component response? For example, how would you know that the conversionResult variable can be used as shown in the dialog flow editor lines 39 - 44? To figure this you, you can use the skill tester.

To learn about the structure of a data object returned by a custom component, stop after processing the custom component, and then use the Variables section in the Conversation tab of the skill tester to explore the variable's content, as described in these steps.

  1. Switch to the skill, and open the skill tester.
  2. Reset the tester.
  3. Enter hi.
  4. Select a base currency.
  5. Enter a value for the amount.
  6. Select one or more target currencies.
  7. Look at the Variables section displayed on the right side of the tester:
    Variables view
  8. Fully expand the conversionResult variable to see the structure of the data object as shown here.
    expanded variables

    You can see the conversionResult object's properties, array items, and subproperties.


more informationWant to Learn More?