0

Watson Assistant only supports one Webhook url. The issue is I have multiple nodes in Assistant that need to call different "Actions" I have hosted in IBM Cloud Functions. How can I do that? I tried to code and "Action" that uses the NPM Axios to call the other "Actions" but it fails as it lacks authentication.

Can someone tell me how to do it? I need the BASE URL to be athenticated via my IBM Cloud user API to grant access to my namespace.

this is the action I created that acts as a "Dispatch" for webhooks for Watson Assistant.

/**
 *
 * main() will be run when you invoke this action
 *
 * @param Cloud Functions actions accept a single parameter, which must be a JSON object.
 *
 * @return The output of this action, which must be a JSON object.
 *
 * 
 * Version: 1.5 beta (API HUB)
 * Date: 24/04/2020
 * 
 */

const axios = require("axios");
// Change to your "BASE_URL". Type in the "Web Action" url without the name of it at the end. (must NOT contains the end '/')
// All "Actions" must be within the same namespace.
const BASE_URL = "https://jp-tok.functions.cloud.ibm.com/api/v1/web/
const POST = "post";
const GET = "get";
const ANY = "any";
const ALL = "all";

/* List all your API methods
    1. method - API Name (This is the "Actions" name at the end of the Web Action URL or just the name)
    2. attr - Attributes that should be available in the params object
    3. rule - Currently supports 2 rules;
                a) any - params is valid if "any" of the attributes are present
                b) all - params is valid only if all attributes are present
    4. httpmethod -Supports "POST" and "GET"
    5. contains - Use for validating GET URL parameters
*/
const API_METHODS = [{
        method: "Emails", // Change to your API method "Please put the function name located at the end of the url without "/" example "Email"
        attr: ["client_email", "department_email"],
        rule: ANY,
        httpmethod: POST,
        contains: null
    },
    {
        method: "testapi", // If Watson needs to "GET" information to a user or athenticate a user
        attr: [],
        rule: ALL,
        httpmethod: GET,
        contains: "?ID="
    },
]

// Returns true if the "params" is valid for the given API method
function isValidParam(method, params = {}) {
    var attributes = [];
    attributes = method.attr;
    var isAny = method.rule === ANY;
    for (let index = 0; index < attributes.length; index++) {
        const attr = attributes[index];
        if (isAny) {
            if (Object.hasOwnProperty.call(params, attr)) {
                return true;
            }
        } else {
            if (!Object.hasOwnProperty.call(params, attr)) {
                return false;
            }
        }
    }

    if (attributes.length === 0 && method.contains) {
        return (JSON.stringify(params).indexOf(method.contains) > -1)
    }

    // if the code reaches this position, inverse of "isAny" should return the actual validation status.
    return !isAny;
}

async function main(params) {
    var result = [];

    // Stop on first failure
    // We iterate through all API methods. Because there can be more than one matching API for the given param type
    for (let index = 0; index < API_METHODS.length; index++) {
        const apiMethod = API_METHODS[index];
        const url = BASE_URL + '/' + apiMethod.method;

        if (isValidParam(apiMethod, params)) {
            let response = apiMethod.httpmethod === POST ?
                await axios.post(url, params) :
                await axios.get(url + params); // Expects the parameter to be a string in this case like '?id=345343'

            console.log(response);

            result.push({
                sent: true,
                url: url,
                request: params,
            });
        }
    }

    return {
        sent: true,
        details: result
    };
}
// THe part of the code that needs to be copied to call other functions within the namespace.


/* const API_METHODS = [{
 method: "Emails", // Change to your API method "Please put the function name located at the end of the url without "/" example "Email"
 *   attr: ["bamboo_email", "latitude_email", "latest_r_email", "department_email"],
    rule: ANY,
    httpmethod: POST,
    contains: null
},
{
    method: "testapi", // If Watson needs to "GET" information to a user or athenticate a user
    attr: [],
    rule: ALL,
    httpmethod: GET,
    contains: "?ID="
},
]  */

When I run it in Watson Assistant I get the following error:

Webhook call response body exceeded [1050000] byte limit.response code: 200, request duration: 591, workspace_id: 150088ee-4e86-48f5-afd5-5b4e99d171f8, transaction_id: a8fca023d456d1113e05aaf1f59b1b2b, url_called: https://watson-url-fetch.watson-url-fetcher:443/post?url=https%3A%2F%2Fjp-tok.functions.cloud.ibm.com%2Fapi%2Fv1%2Fweb%2F23d61581-fa68-4979-afa2-0216c17c1b29%2FWatson+Assistant%2FAssistant+Dispatch.json (and there is 1 more error in the log)

larry walker
  • 123
  • 6
  • Q: What happens if the webhook call response is less than 1,050,000 bytes? – FoggyDay Apr 25 '20 at 05:31
  • It's failing the authentication which creates a stack overflow of errors. How can I add API authentication to the base url in my code? – larry walker Apr 25 '20 at 06:53
  • What type of authentication is needed for calling out to the other API? You typically add basic auth (username / password). In your Cloud Functions environment you have access to an environment variable with the current API key. You can use that as password for some calls or to obtain an auth token. – data_henrik Apr 27 '20 at 05:54
  • THe problem is the namespace is using the new IAMTOKEN method of authentication. Now, I'm trying to figure out how to create a Cloud Foundry namespace. Is it still possible? – larry walker Apr 29 '20 at 13:32
  • Larry, yes you can. The Watson Assistant doc's detail the need for the to be a CF-cloud function. https://cloud.ibm.com/docs/assistant?topic=assistant-dialog-webhooks Also: the IBM Cloud Doc's detail how to create a CF based cloud function. Look under namespaces .. https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-namespaces#what-do-i-do-if-i-have-a-cloud-foundry-based-namespace- – timd May 01 '20 at 11:06
  • Also, under the cloud function "Endpoint" menu option, you should see a APIKey link. This will have a value, the first part is your user name, the second part the password. It shown however as one string username : password. – timd May 01 '20 at 11:08

0 Answers0