About Developing Custom Components with the SDK
Each state in the skill uses either a system component or a custom component.
System components are built into skills and are always available. They provide actions such as outputting text and setting variables. Custom components provide access to business systems such as databases and CRM systems.
To develop a complete custom component, you create an API in Oracle Mobile Hub and define its endpoints along with a backend, which controls access to the API. After the API and backend are defined, you create a connector in Oracle Mobile Hub. The purpose of the connector is to abstract away the connection details to the system of record, removing the need to hard-code the connection details in the implementation. Finally, you write the API’s implementation and upload it to Oracle Mobile Hub.
Create the Custom Component
Define the API Endpoints
To define the endpoints for the custom component:
- In the side menu, expand Development and click APIs.
- Click New API and select API.
- Enter a name and a short description for the API and click Create.
- When the API page opens, click Endpoints.
- Click New Resource.
- In the Resource Path field, enter components then click Methods.
- Click Add Method and select GET.
- When the page for the components endpoint opens, click Save.
- Go back to the Endpoints page and click the plus sign beside the components resource. A nested resource is added.
- In the Resource Path field for the new resource, enter {componentName} then click Methods.
- Select Required then click Add Method and select POST.
- Click Save.
Next, click Security and make sure that the Login Required switch is off.
Create and Set up the Backend
A backend acts as a secure gateway between a bot and its custom components, which are implemented as one or more APIs.
After creating the backend, you associate one or more APIs with it. The associated APIs are accessed through the backend, which provides the base URL for the API and handles authentication.
- In the side menu, expand Development and click Backends.
- Click New Backend.
- Enter a name and a description for the backend and click Create.
- After the backend is created, associate an API to the backend.
Create the Connector
Before you begin, gather the following information:
-
The Swagger document that describes the API that you're connecting to. If you don't have a Swagger document, then you need the base URL of the API.
-
The security credentials of the API that you are connecting to. Connectors support OAUTH, basic auth, SAML, and JWT.
To create the Connector:
- In the side menu, expand Development and click Connectors.
- Click New Connector and select REST.
- Enter a name and a description for the connector and click Create. The configurator opens to the General page.
- Click Descriptor and enter the location of the Swagger document. If you don't have a Swagger document, select I don't have a descriptor and enter the base URL of the API.
- Click Security and set the security policies for the connector.
- Click Test and test the connection to make sure that the connector is working. For example, if you are connecting to a database, make sure that you can send an SQL statement and get the result.
- When you are done testing, click Done.
Write the Implementation Code for the Custom Component
After you've defined the API endpoints and set up the backend, you're ready to develop the implementation of the custom component.
The following sample shows the internal structure of a custom component that provides an order number service for a skill bot that takes online orders for a company that sells t-shirts.
tshirtordertaker
\---tshirtordertaker
| package-lock.json
| package.json
| tshirtordertaker.js
|
+---components
| OrderNumber.js
|
+---lib
| config.js
| database.js
The sample shows a suggested layout of the file structure. The main
field in package.json
points to tshirtordertaker.js
. Within tshirtordertaker.js
, you initialize the component middleware, where you define the location of the file or files that implement the custom component.
The following sample shows what thsirtordertaker.js
looks like. The location of the custom component implementation is defined in the register option, which in this case is the ./components
directory.
/**
* The ExpressJS namespace.
* @external ExpressApplicationObject
* @see {@link http://expressjs.com/3x/api.html#app}
*/
const OracleBot = require('@oracle/bots-node-sdk');
/**
* Mobile Cloud custom code service entry point.
* @param {external:ExpressApplicationObject} service
*/
module.exports = function(service) {
OracleBot.init(service, {
logger: console
});
OracleBot.Middleware.customComponent(service, {
cwd: __dirname,
baseUrl: '/mobile/custom/TShirtOrderTaker/components',
register: './components',
});
};
The baseUrl value is in the form of /mobile/custom/<API-Name>/components
where <API-Name> is the name that you gave the API when you created it in Oracle Mobile Hub. The register value is the directory that contains the file or files that implement the service.
In this case, the components
directory has one file, called OrderNumber.js
. This file contains the metadata
and invoke
functions that the bot system requires of every custom component. The following snippet shows what the beginning of OrderNumber.js
looks like:
'use strict'
const { DBConnector } = require('../lib/database');
const { DB_CONNECTOR_NAME, DB_CONNECTOR_VERSION } = require('../lib/config');
/**
* normalize color for db queries
* @param {string} color
*/
module.exports = {
metadata: () => ({
name: "OrderNumber",
properties: { customerID: { type: "string", required: true } },
supportedActions: [
"instock",
"backorder"
]
}),
invoke: (conversation, done) => {
// deconstruct the conversation to get connectors instance
const { oracleMobile } = conversation;
if (!oracleMobile) {
conversation.error(true);
conversation.reply('The oracleMobile reference was not found. There might be a problem with this API');
done();
} else {
// instantiate DBConnector helper class with backend connectors object
const db = new DBConnector(oracleMobile.connectors, DB_CONNECTOR_NAME, DB_CONNECTOR_VERSION);
.
.
.
In this case, a connection to a database is made through a connector API in Oracle Mobile Hub. In the example structure shown earlier, the code for DBConnector
would be implemented in database.js
. The code for your own implementation will of course be different, but the structure should be the same.
Upload the implementation
The package that you upload is called an implementation archive, and is contained in a .zip file.
The process of uploading the implementation as described here is a manual process. However, command-line options are available. See the Oracle Mobile Hub documentation for instructions on how to download, set up, and use the Custom Code Test Tools that are on Oracle Technology Network (OTN).
- Zip the top-level directory to create an implementation archive.
- Upload the package to your API.
- Log into Oracle Mobile Hub and open your API.
- On the API page, click Implementation.
- Upload the API. You can click Upload an implementation archive or drag it onto the page.
Test the Implementation
After you upload your implementation, you should test it.
- Click Test at the top of the page.
- Make sure that the GET /components endpoint is selected
- Select the appropriate Backend.
- Set the Authentication Method.
- Click Test Endpoint.
If the test succeeds, you should see a response status of 200 and a JSON payload. The payload should have the same structure as the following JSON:
{
"version": "1.1",
"components": [
{
"name": "OrderNumber",
"properties": {
"customerID": {
"type": "string",
"required": true
}
},
"supportedActions": [
"instock",
"backorder"
]
}
]
}
Add the Custom Component to Your Bot
After the custom component is deployed and ready for operation, add it to your skill bot.
You add the custom component by first setting up a component service in the skill bot UI. Next, you edit the BotML flow to add the state that calls the custom component and the states that handle the response. After everything is set up, test the bot.
Create a Service for Your Custom Component
To set up a service, you need the connection and authentication information of the service that hosts your custom component.
You need the backend ID that hosts the API for your custom component and either the anonymous key for the backend or the credentials for a mobile user. You can get the backend ID and the anonymous key from the summary page for the backend that you created to host the API.
You also need the URL that the service uses to retrieve the custom component's metadata. You can form the metadata URL by copying the URL for the API from the General page of the API Designer and then appending /components
to it.
- In the designer UI for your skill bot, open the components editor.
- Click + Service.
- Enter the connection and authentication information for the service that hosts your custom component. If you're using an Oracle Mobile Hub backend, make sure that you append the Metadata URL with
/components
. - Click Create.
Update the Dialog Flow
The dialog flow in the following procedure is for a t-shirt order taker skill bot. It uses a custom component called OrderNumber, within a state called Get Order Number. When the bot enters this state, the custom component implementation is called by the system. The sample shown corresponds to a custom component which takes a customerID as the input. In this case, the ID is hard-coded but you can also pass in a variable. The custom component also has access to information that the skill bot collected from the user, such as quantity, size, and color. Before responding with either "instock" or "backorder", the custom component sets a variable called orderNumber.