0

_

MY CHALLENGE:

I would like to access a third party Rest API from within my Lambda function. (e.g."http://www.mocky.io/v2/5c62a4523000004a00019907").

This will provide back a JSON file which I will then use for data extraction

_

MY CURRENT CODE:

var http = require('http');

exports.handler = function(event, context, callback) {
    console.log('start request to Mocky');

    http.get('http://www.mocky.io/v2/5c62a4523000004a00019907', function(res) {
            console.log(res);

        })
        .on('error', function(e) {

            console.log("Got error: " + e.message);
        });
};

This does not throw an error but also does not seem to provide back the JSON

_

MY OPEN QUESTIONS:

1) How can I extract the JSON so that I can work on it

2) I will probably need to also send through an Authentification in the request header (Bearer) in the future. Will this also be possible with this method?

Geole
  • 356
  • 1
  • 5
  • 17

2 Answers2

1

The problem is likely that your lambda function is exiting before logging the response.

We use Authorization headers all the time to call our lambdas. The issue of if you can use one to call the third party API is up to them, not you, so check the documentation.

Since your HTTP call is executed asynchronously, the execution of the lambda continues while that call is being resolved. Since there are no more commands in the lambda, it exits before your response returns and can be logged.

EDIT: the http.get module is difficult to use cleanly with async/await. I usually use superagent, axios, or request for that reason, or even node-fetch. I'll use request in my answer. If you must use the native module, then see EG this answer. Otherwise, npm install request request-promise and use my answer below.

The scheme that many people use these days for this kind of call uses async/await, for example (Requires Node 8+):

var request = require('request-promise')

exports.handler = async function(event, context, callback) {
    console.log('start request to Mocky');
    try {
        const res = await request.get('http://www.mocky.io/v2/5c62a4523000004a00019907')
        console.log(res)
        callback(null, { statusCode: 200, body: JSON.stringify(res) })
    }
    catch(err) {
        console.error(err.message)
        callback('Got error ' + err.message)
    }
};

The async/await version is much easier to follow IMO.

Everything inside an async function that is marked with await with be resolved before the execution continues. There are lots of articles about this around, try this one.

Matt Morgan
  • 4,900
  • 4
  • 21
  • 30
  • Dear Matt, thank you so much for your help! FOR THE FIRST EXAMPLE: At first the process exited before completing the request. I then added "async" and it run successful. Where would I **put a "console.log" statement** to track if I actually receive any input from the API? FOR THE SECOND EXAMPLE: I first received an error for the catch statement. I then added another "}" after the try statement to complete this. However when I then try to run the program I get an error saying that it **cannot find the "promisify" module** – Geole Feb 12 '19 at 12:23
  • Put the console logs in the flow _before_ you invoke the callbacks in either example, and that should work. You need Node 8+ to use `promisify`, and 7.6 or better to use `async/await`. Lambda accepts 8.10 these days, so upgrade if you can. I've edited my answer to include this additional information. – Matt Morgan Feb 12 '19 at 12:25
  • I'm on Node.js 8.10 and still get an error: ### Response: { "errorMessage": "Cannot find module 'promisify'", "errorType": "Error", "stackTrace": [ "Function.Module._load (module.js:474:25)", "Module.require (module.js:596:17)", "require (internal/module.js:11:18)", "Object. (/var/task/index.js:2:17)", "Module._compile (module.js:652:30)", "Object.Module._extensions..js (module.js:663:10)", "Module.load (module.js:565:32)", "tryModuleLoad (module.js:505:12)", "Function.Module._load (module.js:497:3)" ] } ### – Geole Feb 12 '19 at 12:30
  • Dear Matt, thank you again for your help. I have changed to the Typicode API ("https://jsonplaceholder.typicode.com/posts") just to make sure that there is no failure on the API end. I have changed the "http" parts into "https". However. I now get the code to work but get an error response of "undefined". Any ideas? – Geole Feb 12 '19 at 12:41
  • @Geole I forgot that the native `http.get` returns a stream. I never use it in practice because the syntax is more convoluted. I've simplified my answer to show how to make this request with `request-promise`. – Matt Morgan Feb 12 '19 at 12:58
  • Dear Matt, thank you again for your support. I used one of the approaches from the examples using the native module and it worked (including http header). As I'm always looking to improve my coding I would like to know if you could recommend me a page where I can learn how to install the npm libraries in the Lambda web module. Then I can also try your code! Thanks! – Geole Feb 12 '19 at 21:04
  • I suggest checking out the Serverless framework. It removes a lot of the pain from AWS Lambda, and works with other FaaS providers (Azure, Google Cloud Functions) also. https://serverless.com/ – Matt Morgan Feb 13 '19 at 00:29
0

There are a lot of guys having an equal problem already solved... Look at that or that

Ore
  • 972
  • 2
  • 12
  • 24
  • Dear Ore, thank you for your answer. I'm less struggling with the aysnchronous call as more with the ability to actually connect to the API and retrieve the data – Geole Feb 12 '19 at 12:33
  • Oh, i must have overlooked that. However, i strongly recommend you to listen to Matt Morgen, especially about the Serverless framework which takes away much of the struggle. – Ore Feb 13 '19 at 14:16