Calling API into hook

Is there any way to use the output of an API in a hook?

This is my current hook that makes the bot speak when a user opens up the webchat:

"use strict"
if (event.type === 'proactive-trigger') {
  const eventDestination = {
    channel: event.channel,
    target: event.target,
    botId: event.botId,
    threadId: event.threadId
  }

  event.setFlag(bp.IO.WellKnownFlags.SKIP_DIALOG_ENGINE, true)

  // Make the bot respond with custom content instead


  // Make the bot respond with custom content instead
  bp.cms.renderElement('builtin_text', { text: 'Hi I&#39m Bot.' + 'Click one of these buttons presented.'+
  '<br><br><ol><li><button class=\"downloadButtonMenu\" onClick=\"window.open('API_LINK_OUTPUT0', '_self'); return false\"><strong>button 1</strong></button></li>" +
  "<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('API_LINK_OUTPUT1', '_self'); return false;\"><strong>button2</strong></button></li>" +
  "<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('API_LINK_OUTPUT2', '_self'); return false;\"><strong>button3</strong></button></li>" +
  "<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('API_LINK_OUTPUT3', '_self'); return false;\"><strong>button4</strong></button></li>" +
  "<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('API_LINK_OUTPUT4', '_self'); return false;\"><strong>button5</strong></button></li></ol>", typing: true }, eventDestination).then(payloads => {bp.events.replyToEvent(event, payloads)})}
}

Notice that they’re presented with a list of buttons they can click that opens a link in a seperate tab. I need to be able to replace the link that is returned from the api into the API_LINK_OUTPUT sections.

Anyway to do this?

Hey @av_botpress!

You can use the axios libary to make HTTP calls to your API from within the hook. axios is already included in Botpress, so it will work out of the box in your hook.

Here is how I would modify your code to use axios:

"use strict"
const axios = require('axios')

if (event.type === 'proactive-trigger') {
  const eventDestination = {
    channel: event.channel,
    target: event.target,
    botId: event.botId,
    threadId: event.threadId
  }

  event.setFlag(bp.IO.WellKnownFlags.SKIP_DIALOG_ENGINE, true)

  const { data } = await axios.get('your API url')
  const API_LINK_OUTPUT0 = // ... extract link from data
  const API_LINK_OUTPUT1 = // ... extract link from data
  const API_LINK_OUTPUT2 = // ... extract link from data
  const API_LINK_OUTPUT3 = // ... extract link from data
  const API_LINK_OUTPUT4 = // ... extract link from data

  // Make the bot respond with custom content instead


  // Make the bot respond with custom content instead
  bp.cms.renderElement('builtin_text', { text: 'Hi I&#39m Bot.' + 'Click one of these buttons presented.'+
  `<br><br><ol><li><button class=\"downloadButtonMenu\" onClick=\"window.open('${API_LINK_OUTPUT0}', '_self'); return false\"><strong>button 1</strong></button></li>` +
  `<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('${API_LINK_OUTPUT1}', '_self'); return false;\"><strong>button2</strong></button></li>` +
  `<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('${API_LINK_OUTPUT2}', '_self'); return false;\"><strong>button3</strong></button></li>` +
  `<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('${API_LINK_OUTPUT3}', '_self'); return false;\"><strong>button4</strong></button></li>` +
  `<br><li><button class=\"downloadButtonMenu\" onclick=\"window.open('${API_LINK_OUTPUT4}', '_self'); return false;\"><strong>button5</strong></button></li></ol>`, typing: true }, eventDestination).then(payloads => {bp.events.replyToEvent(event, payloads)})}
}

Hope this helps!

Thank you very much!!! You saved me! I just have a couple of questions.

  1. Why are the back ticks used? (Just so I don’t make mistakes again in the future when calling variables inside strings)

  2. How can I call the urls (that are generated from the api) stored inside data? data.0 and data[0] isn’t working. The output of the api is an array of urls is as follows:[“https://LINK0”,“https://LINK1”,“https://LINK2”, etc]

  3. If I wanted to use this api for the CSS file (in the index.html extraStyleSheet config) how can I call the api in the html file?

  1. The back ticks are use for string templating in Javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

  2. If you want to call the urls, I suggest you use axios again. You can use await axios.get("https://LINK0") for example

  3. I’m not sure what you mean by using “this api for the CSS file”. However, if you want to make HTTP calls from the browser, I suggest you have a look at the fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Thank you for these explanations! I’m still a little confused at how to call the api.

The API I created outputs urls. I don’t understand how using the get command would grab that response since the get command calls where the API is hosted from.

I used this API in an action that was as follows:

const axios = require('axios')

  /**
  * @title URL
  * @category 
  * @author 
  */

  const UrlAPI = async () => {
    const { data } = await axios.get('http://10.123.456.197:3000/get_url')
    session.response = data
  }
  return UrlAPI()
/** Your code ends here */

So in this case I just called {{session.response.0}} to get the first URL in the array.

Also, I ran the bot with the changes you suggested and I got:

2019-11-07 15:28:51 error  An error occured on "botspeakfirst.js" on "before_incoming_middleware". SyntaxError: await is only valid in async function [SyntaxError, await is only valid in async function]
STACK TRACE
vm.js:15
  const {data} = await axios.get('http://10.123.456.197:3000/get_url');
                 ^^^^^
SyntaxError: await is only valid in async function