question

Nikki.13 avatar image
Nikki.13 asked ·

Invoking a rest API from within a lambda function

I've been trying to integrate a new skill for Alexa . As part of doing so, I'd like to call an external API ( not hosted on AWS ) from within the lambda function. I've been browsing the web for the past week, several posts indicate code snippets that have worked for them and several posts indicate that this is not possible without creating a VPC : http://docs.aws.amazon.com/lambda/latest/dg/vpc.html

Here's an example of a code snippet that claims that it worked; however, the API call never gets invoked and there are no error messages: https://github.com/steckdev/AlexaCustomSkills

The question is how can one make a restful call to an external API from a standalone lambda function?

alexa skills kitlambdaresponse
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Anand@Amazon avatar image
Anand@Amazon answered ·

Hi Nikki,

After looking into your lambda code it's look like you are using 'http' connection to call API. Try to use 'HTTPS' connection to call URL and it will resolve all your issues.

Use api which supports HTTPS connections to avoid any issues.

Please follow above recommendations and lets us know if you have any further issues.

Please refer below link for get more details:

https://github.com/robm26/SkillsDataAccess/blob/master/src/CallService/index.js

4 comments
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hmmm, http API connections work from Lambda. If the API has a https endpoint then great, but if it's http then that will still work.

1 Like 1 ·

Thanks Anand, after days of struggling to connect to my REST API from within Lambda I finally have it working.

1 Like 1 ·

This solved my problem as well! Thank You @Anand@Amazon

0 Likes 0 ·

Hi @Anand@Amazon Problem Solved!!!! Thank You!

0 Likes 0 ·
Andy Whitworth avatar image
Andy Whitworth answered ·

For a GET then something like this

const http = require('http');

function callAPI(params, callback) {
  console.log('In callAPI, params: ' + params);
    var options = {
      method: 'GET',
      host: 'api.wherever.com',
      path: '/apipathname/whatever/' + params,
      headers: {
        'accept': 'application/json',
      }
    };
    var dataStr = "";
    const req = http.request(options, function (response) {
      response.on('data', data => dataStr += data);
      response.on('end', () => callback(JSON.parse(dataStr)));
    }).on('error', err => // handle error
	);
    req.end();
}
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

cheko avatar image
cheko answered ·

If your code is in Python, then below can help, Assuming its a Simple API, accepting the API key as part of the Url (eg Google Maps API)

import json
from urllib.request import urlopen

response = urlopen("Api url")
out = json.load(response)

.
.
# Parse the response (Assuming in Json) as required.
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Nikki.13 avatar image
Nikki.13 answered ·

Thank you for the responses. The main problem is that it seems like within the Lambda function I'm unable to call an external API. ( Not having an AWS infrastructure ) . There are two theories that I'm running with:

1) Maybe it needs to be in a VPC with subnets that have an internet gateway to get internet access out - I really don't want to explore this option as it will add cost and extra overhead for no reason at all . Depending on where I read , I find conflicting information about this. Hence I posted this question on Amazon forum.

2) This theory is that Alexa ends the lambda's event loop when this.emit() is called. When I call request() - which is async - and then immediately calling this.emit() could end the event loop and leave the response unhandled.

Regardless of the above theories, I've followed everything here to the dot: https://www.hackster.io/steckdev/alexa-skills-rest-api-using-http-071868

but even this that supposedly works does not actually invoke the API.

Does anyone know whether or not Amazon recently made the changes such that making an external call is not allowed ? ( I can't imagine as there are several skills that rely on making external calls for simple things )

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

newuser-99133625-578a-4b74-95bc-16c78d0cd4fb avatar image
newuser-99133625-578a-4b74-95bc-16c78d0cd4fb answered ·

I'm having the exact same problem; accessing an external REST API from within an Alexa Skill. I tried the suggested sample code, and still didn't have any luck. I can see that no requests are reaching my web service.

2 comments
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

@AndyW I privately sent this user a message and we both tried above snippet and nothing changed for us.. Do you have a repo you can point us to ?

2 Likes 2 ·

Can you paste in the output from the Cloudwatch Log when you invoke your lambda ?

0 Likes 0 ·
Andy Whitworth avatar image
Andy Whitworth answered ·

AWS lambda code can 100% call external webservices, I've got at least three skills which do this, to both http:// and https:// endpoints.

No magic configuration required, it just works.

"This theory is that Alexa ends the lambda's event loop when this.emit() is called. When I call request() - which is async - and then immediately calling this.emit() could end the event loop and leave the response unhandled."

If you do the above then that's your problem. Your lambda execution will terminate without the webservice invocation completing. You need to wait for the webservice call to complete before calling emit().

From the Node ASK Readme:

  • When any of the response events are emitted :ask, :tell, :askWithCard, etc. The lambda context.succeed() method is called, which immediately stops processing of any further background tasks. Any asynchronous jobs that are still will not be completed and any lines of code below the response emit statement will not be executed. This is not the case for non responding events like :saveState.
1 comment
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

@AndyW Thank you for your reply.

Even when I try that ( whether it be using my own code or a snippet from others ) I don't see any WS calls made. Do you have some sample code that you can share with me? I have tried implementing your snippet below into my own code and still nada.. I've also followed up with @NewUser-99133625-578a-4b74-95bc-16c78d0cd4fb on this thread and compared our code snippets .. still same problem :-( He also tried below snippet

5 Likes 5 ·
Steve avatar image
Steve answered ·

@Nikki.13 Asynchronous HTTP calls act differently than synchronous calls.

What's been described throughout this thread is a common hurdle with lambda-based custom skills. As @AndyW noted, you're probably walking into an early context.succeed() issue. Many Node HTTP clients, including the request library, force you to use asynchronous programming which means your normal program flow will not work.

Instead of lines of code executing after other lines of code have completed, in asynchronous programming you have to provide a callback function (or a Promise success/error handler). It's in your handler that you must call context.succeed(), :ask, :tell, :askWithCard, etc - anything that sends speech back to Alexa.

This means that you will probably have to change much of your current program flow to suit the callback/Promise pattern, otherwise you'll continue hitting your head against this brick wall. If you can post your code it'll be easier to point out what needs to be changed.

2 comments
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thanks @Steve To troubleshoot this problem, I started from this lambda function : https://github.com/steckdev/AlexaCustomSkills/blob/master/GospelLibraryReader/AWSLambdaFunction/Lambda%20Function.json

I was unable to get this to work.. I then modified this example and added my own URL just so that I can see whether or not I see calls coming through. Similarly this also does not work ( I've replaced the URLs with placeholders) . lambdafunction.txt

1 Like 1 ·
lambdafunction.txt (21.7 KiB)

@Nikki.13 I know these are silly questions, but I have to ask: Does your lambda function have the Alexa trigger enabled? Do you get any other log output in CloudWatch when you use the voice simulator or physical Alexa device to invoke your skill? It might be worth adding some console output so you can tell if you've reached different parts of your lambda.

One thing that stands out to me is that you're building all of the Alexa interactions manually, which might have resulted in some insidious typo. You might consider using the AWS Alexa SDK for Node - it's a lot easier to deal with the inbound requests and outbound speech/cards.

After a look through your code, I couldn't say what's wrong, but I've attached a heavily modified example of a working skill. (Wow, SUPER frustrating that uploading a file destroys whatever you've typed out!)

The example shows what I consider a typical lambda skill using the AWS Alexa SDK. You're welcome to use this as a base for your skill. Honestly I don't know what the problem is with the code you have, but you will probably find it easier to troubleshoot if you use the attached code instead. Start small, test often, make sure your skill is being invoked properly without the web service interaction, then work your way up to a full skill implementation.

example.txt
1 Like 1 ·
example.txt (6.1 KiB)
Chen Levkovich avatar image
Chen Levkovich answered ·

Follow this simple tutorial, it includes connecting to backend web APIs Building Your First Conversational App

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

newuser-cba39619-ed04-4a69-99d9-69eb9c3e67f9 avatar image
newuser-cba39619-ed04-4a69-99d9-69eb9c3e67f9 answered ·

Hey Hi,

I am having a similar problem. Where you able to solve the problem. Please share the solution.

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

newuser-5fb8266e-cdf4-4af3-afec-5bfaf1f8e0af avatar image
newuser-5fb8266e-cdf4-4af3-afec-5bfaf1f8e0af answered ·

Same problem , calling external api were we able to solve

1 comment
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Because this thread is quite old, can you create a new thread and describe your problem there? Also post some code which could be causing the issue.

1 Like 1 ·