How to make async calls in v4 Component handler?

amazon-alexa

#1

I’m trying to call a rest service from within a component handler. Unfortunately when I use async/await all speech output in my Alexa skill is lost. I used the request example from v3.


#2

How long is the wait?

I’m doing this in the current version of my new-sounds-on-demand skill, and as long as the REST routine returns quickly I’m fine. When it was taking an unreasonably long time (due to a bug in my code), the Alexa interaction timed out before I could respond.


#3

The complete call takes about 300ms and about 1KByte of data is transported.
Actually everything looks normal.
I also tried it with another lightweight REST call with the same result.
Maybe there’s more to it than a simple async/await within a handler.


#4

Hi @wkl, welcome to the Jovo community :tada:

Could you share your handler code please?


#5

What happens if you dummy out that call? That would establish clearly whether the async/wait is actually the relevant factor.


#6

Hello there,

Here’s an example how an async call inside a component handler could look like:

import { BaseComponent, Component } from '@jovotech/framework';

@Component()
export class ExampleComponent extends BaseComponent {
  async someHandler() {
    await this.$send('Hello world! This is an async call.');
  }
}

I hope this helps.


#7
async handleMyData(){
    const res = await axios.get('http://localhost:8080/rest/items?recursive=false', {
      headers: {
        Accept: 'application/json'
      },
    }).then(response => {
      return response.data;
    }).catch(err => {
      console.log(err);
    });
    return this.$send({message:'Data returned',listen: false});
  }

The result is the same for request and axios lib, no alexa response.


#8

Could you try this?

async handleMyData(){
    const res = await axios.get('http://localhost:8080/rest/items?recursive=false', {
      headers: {
        Accept: 'application/json'
      },
    });
    return this.$send({message:'Data returned',listen: false});
  }

It would also be good to see how you’re calling the handleMyData handler. From a different handler or is it entered with an intent?


#9

I tried your code, but unfortunately it doesn’t work either.
Here’s how I call the handler:

START() {
    return this.$redirect(TemperatureComponent, 'handleMyData');
  }

I added the redirect to test with different handler implementations.


#10

Could you share the response JSON?


#11

Here some results of my async/await tests:
If I implement everything in the GlobalComponent, then it works fine.
However, when I redirect to another component via $redirect method and call a handler that uses async/await I get an incorrect response.
Attached the incorrect response for redirect:

{
	"body": {
		"version": "1.0",
		"response": {
			``"shouldEndSession": false,
			"type": "_DEFAULT_RESPONSE"
		},
		"sessionAttributes": {
			"createdAt": "2021-12-17T17:22:13.564Z",
			}, "data": {},
			"id": "amzn1.echo-api.session.8f33d48f-3508-417a-95bb-2bb1fd0f0d9f",
			"state": [
				{
					"component": "TemperatureComponent"
				}
			],
			}, "isNew": true,
			"updatedAt": "2021-12-17T17:22:13.564Z"
		}
	}
}

In the response above outspeech part is missing and I get type “_DEFAULT_RESPONSE” and property ‘shouldEndSession’ is false instead of true.
All testing was done for the Alexa platform only.


#12

Hey @wkl

Could you share your code in handleMyData?

I tried to reproduce it with a dummy API call.

// AsyncComponent.ts
@Component()
export class AsyncComponent extends BaseComponent {
  async handleMyData() {
    const result = await apiCall();
    return this.$send( { message: 'Result is: ' + result });
  }
}

function apiCall() {
  return new Promise((resolve) => {
    setTimeout(() => {
      return resolve('okay');
    }, 1000);
  })
}

// GlobalComponent.ts
@Global()
@Component()
export class GlobalComponent extends BaseComponent {
  LAUNCH() {
    return this.$redirect(AsyncComponent, 'handleMyData');
  }
}

It works as expected.


#13

Does it time out, or is the response returned immediately?


#14

For a description of handleMyData() please see my previous post.
I moved all my code to the GlobalComponent where it works just fine.
Not sure what the problem was with the redirect.