javarestspring-mvcactions-on-googlegoogle-assist-api

How to process a request to an external REST service and return the response to Google Assistant?


I am using Java to create an app for Google Assistant that will call an external REST API and return certain responses based on trigger phrases. I currently can use the Default Welcome Intent to return simple text responses through the Actions on Google simulator. However, when I try to call an external REST API and send back a response, the simulator returns a message that says:

"MalformedResponse: Failed to parse Dialogflow response into AppResponse because of empty speech response."

I am using the org.springframework.web.client.RestTemplate from Spring-framework to process the result from the REST Service (https://fitzroi-rest-api-0525.appspot.com/rest/Fitz) with the following call: greeting = restTemplate.getForObject("https://fitzroi-rest-api-0525.appspot.com/rest/{name}", Greeting.class, givenName); (This works well in a regular Spring project, but not within the Actions on Google Intent)

An example training phrase for my test app is "Tony is sending greetings." From here I am extracting "Tony" as a @sys.given-name entity in Dialogflow. This name is then passed to the REST serivice for processing. The REST service is an MVC app that is running in a separate Google Cloud project from the Google Assistant App.

Please let me know if this is a good approach to consume a REST service using Dialogflow fullfillment webhook.

Below is a sample code from my webhook that is trying to consume the REST service.

@ForIntent("process-greeting")
  public ActionResponse greetingProcessor(ActionRequest request) {
    LOGGER.info("Trying to process greeting intent");
    ResponseBuilder responseBuilder = getResponseBuilder(request);

    String givenName = (String) request.getParameter("given-name");


    if (givenName != null && !givenName.isEmpty()) {
      RestTemplate restTemplate = new RestTemplate();
      Greeting greeting = null;
      greeting = restTemplate.getForObject("https://fitzroi-rest-api-0525.appspot.com/rest/{name}", Greeting.class, givenName);

//    LOGGER.info("Attempting to send back " + greeting.getContent() + " to Google Assistant");
      if (greeting == null)
        responseBuilder.add("The rest service did not return a  response.");
      else
        responseBuilder.add(greeting.getContent());
    }

    LOGGER.info("Welcome intent end.");
    return responseBuilder.build();
  }

Solution

  • It seems that since actions-on-google requires thread-safe function calls, the RestTemplate from spring-framework does not work in an app-engine app. I was able to find a walk-around by using a sample code provided by the actions-on-google team on GitHub. This code requires that you parse the results from the URL from within the ActionsApp instead of using a library. For example:

    URL restURL = new URL("http://yourdomain.com/your/rest/call");
    URLConnection conn = restURL.openConnection();
    InputStreamReader reader = new InputStreamReader(
                   (InputStream) conn.getContent());
    JsonParser parser = new JsonParser();
    JsonElement root = parser.parse(reader);
    MyObject = myParseFunction(root);
    
    

    I also had a serious issue (UnKonwnHostException) parsing the results from a remote URL. This documentation was helpful.