4

I am writing a handler for an intent to generate a PDF. This API accepts a POST request with the JSON data and returns a link to the generated PDF. The intent triggers this code but the answer is not added to the agent. Is it possible that the request is not forwarded to the destination? The API seems to not get any requests. Any idea how to solve this?

function fillDocument(agent) {
    const name = agent.parameters.name;
    const address = agent.parameters.newaddress;
    const doctype = agent.parameters.doctype;

    var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
    var xhr = new XMLHttpRequest();
    var url = "https://us1.pdfgeneratorapi.com/api/v3/templates/36628/output?format=pdf&output=url";
    xhr.open("POST", url, true);
    xhr.setRequestHeader("X-Auth-Key", "...");
    xhr.setRequestHeader("X-Auth-Secret", "...");
    xhr.setRequestHeader("X-Auth-Workspace", "...");
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.setRequestHeader("Accept", "application/json");
    xhr.setRequestHeader("Cache-Control", "no-cache");
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var json = JSON.parse(xhr.responseText);
            agent.add(json.response);
        }
    };
    var data = JSON.stringify({...});
    xhr.send(data);
}

EDIT: I proceeded to set up a billing account in GCP, now the call works, but it is async. If I change it to syn by doing this:

xhr.open("POST", url, false);

I get the following error:

EROFS: read-only file system, open '.node-xmlhttprequest-sync-2'

I need it to be async as the response my bot is supposed to send depends on the response from the API. Any ideas on how to go around this?

1 Answers1

3

If you are doing async calls, your handler function needs to return a Promise. Otherwise the handler dispatcher doesn't know there is an async call and will end immediately after the function returns.

The easiest way to use promises with network calls is to use a package such as request-promise-native. Using this, your code might look something like:

var options = {
  uri: url,
  method: 'POST',
  json: true,
  headers: { ... }
};
return rp(options)
  .then( body => {
    var val = body.someParameter;
    var msg = `The value is ${val}`;
    agent.add( msg );
  });

If you really wanted to keep using xhr, you need to wrap it in a Promise. Possibly something like

return new Promise( (resolve,reject) => {

  var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
  // ... other XMLHttpRequest setup here
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      var json = JSON.parse(xhr.responseText);
      agent.add(json.response);
      resolve();
    }
  };

});
Prisoner
  • 49,922
  • 7
  • 53
  • 105