Malformed Lambda proxy response - node.js

I am trying to access a Lambda function using a POST method. When I try to test the POST resource I put in the Request body {"article_url": "http://technewstt.com/bd1108/"}
This makes the API Gateway respond with Execution failed due to configuration error: Malformed Lambda proxy response My code is below.
exports.handler = (event, context, callback) => {
//event = {"article_url": "http://technewstt.com/bd1108/"};
console.log(event.article_url);
var http = require('http');
var TextAPI = require('textapi');
var textapi = new TextAPI({
application_id: "randomn numbers",
application_key: "randomn numbers"
});
textapi.summarize({
url: event.article_url,
sentences_number: 3
}, function(error, response) {
if (error === null) {
response.sentences.forEach(function(s) {
console.log(s);
//var body = JSON.parse(s);
// TODO implement
//callback(null, s);
callback(null, {"statusCode": 200, "body": JSON.stringify(s)});
});
}
});
};
Please note that if I uncomment the second line the API gateway works fine.
Any help with this issue would be greatly appreciated.

You are using Lambda Proxy integration which always expects output of the format http://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
"Malformed Lambda proxy response" is returned if the lambda response format is unexpected. You can enable logging with full request/responses which should show you the response being returned from lambda. Its likely there was an error in you lambda function which returned an error.

Related

how to read API gateway body into json in lambda?

I have an AWS API gateway function connected to the following lambda function:
exports.handler = async (event,context) => {
let buff = new Buffer(event.body,"base64");
let data = buff.toString("ascii");
const response = {
statusCode: 200,
body: JSON.stringify(data + ' Hello from Lambdsa!'),
};
return response;
};
It's a POST function and the current return is:
"----------------------------866060539566167157861191\r\nContent-Disposition: form-data; name=\"email\"\r\n\r\nmyemail.dk\n\r\n----------------------------866060539566167157861191--\r\n Hello from Lambdsa!"
How can I make this base64 decoded content into JSON I can read more easily in my lambda function with the HTTP API?
If you only want to have body in your lambda function and let request and response transformation to be managed by API Gateway, then you can simply go to API Gateway settings of this lambda function and disable Use Lambda Proxy Integration option.
Here is the quick graphic representation of difference between using and not using it :
Also, attaching a screenshot where you would find the option to disable it :
Note: Removed some sensitive info.
Now you simply get the body in lambda function as :
exports.handler = async (body) => {
try {
// Do some operation here
return body;
} catch (error) {
return error;
}
};

AWS API GATEWAY <=> AWS Lambda CORS problem

This is my first time with AWS, I did set up a DynamoDB table as well as created Lambda functions to do CRUD manipulations, I made the functions static at first. Then, I proceeded to create API Gateway methods to access the Lambda functions dynamically.
The method that I try to call is a GET method, it should be callable using JS and from a different domain, I need to enable CORS, unfortunately even after I have it in the header of my lambda function it gives me CORS error:
'use strict';
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-2' });
exports.handler = async (event, context) => {
const ddb = new AWS.DynamoDB({ apiVersion: '2012-10-08' });
const documentClient = new AWS.DynamoDB.DocumentClient({ region: 'us-east-2' });
let responseBody = "";
let statusCode = 0;
var params = {
TableName: "Users",
};
// scan is a function, that is like the SELECT .. WHERE .. clause in SQL
try{
const data = await documentClient.scan(params).promise();
responseBody = JSON.stringify(data.Items);
statusCode = 200;
}catch(err) {
responseBody = `Unable to Scan Users, error: ${err}`;
statusCode = 403;
}
const response = {
statusCode: statusCode,
headers: {
"access-control-allow-origin": "*"
},
body: {
responseBody
}
};
return response;
};
This is the code I have in a VueJS application that should make a request to the GET method in API Gateway:
try{
const res = await axios.get("https://here-goes-my-url");
console.log(res.data);
} catch (err){
console.log(err);
}
this is the error I'm getting:
Access to XMLHttpRequest at 'https://here-goes-the-url' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The Lambda GET method should return all items in the table "Users".
Please help, thanks!
Ok you have your header set.
Have you enabled cors from the API Gateway ?
And when you see CORS errors, they are not always related to CORS in case of AWS lambda as sometimes the response is blocked by API Gateway and the client is still getting a CORS error. I think this is made so it is more difficult to hack, as errors are useful if you are trying to hack the server.
So I would strongly suggest you to test your application first in the API Gateway console.
This will give you a more actionable error. I am guessing this might be related to permissions. Hope this helps.

NodeJS http get method access url in response function

I want to access http request url and parameters in callback function. When I print id with console.log I get error is id undefined. How can I access id and request url?
const Request = require('request');
var id=5;
Request.get('https://example.com/'+id, function (error, response, body) {
console.log("id", id);
}
});
Your code works .may be some syntax error issue,this is the updated
code. I tested it in my console and is working fine.
const Request = require('request');
var id=5;
Request.get('https://example.com/'+id, function (error, response, body) {
if(error) {
return console.dir(error);
}
console.log("id", id);
});
You might need to have a look at the official documentation of the Request package-here and link which explains its usage in detail

Node.js Lambda Function "response is invalid" Amazon Alexa

UPDATE: I had a mistake on my http request endpoint. I had not set the appropriate authentication options so that fixed a lot of errors possibly this specific one.
My question is similar to one here:
Node.js Lambda function returns "The response is invalid" back to Alexa Service Simulator from REST call
However the solution to that question does not solve my problem. So I make an http request call to an xsjs service in Hana cloud. I am getting the 'response is invalid' error message. I can't see why. Here is my function:
// Create a web request and handle the response.
function httpGet(query, callback) {
console.log("/n QUERY: "+ query);
var host = 'datacloudyd070518trial.hanatrial.ondemand.com';
var path = '/LocationInformation/getLocationInfo.xsjs?location=';
var hostname = 'https://' + host + path + query;
var auth = 'user1:D1anafer';
var req = http.request({'hostname': hostname,
'auth': auth
}, (res) => {
var body = '';
res.on('data', (d) => {
body += JSON.stringify(d);
});
res.on('end', function () {
callback(body);
});
});
req.end();
req.on('error', (e) => {
console.error(e);
});
}
And the function that calls it:
'getNewsIntent': function () {
//self = this;
httpGet(location, function (response) {
// Parse the response into a JSON object ready to be formatted.
//var output = JSON.parse(response);
//output = output['change'];
var output = response;
var cardTitle = location;
var cardContent = output;
alexa.emit(':tellWithCard', output, cardTitle, cardContent);
});
},
Thank You
-Diana
Inside your AWS account go to your Lambda function and click on the monitoring tab, where you should see "View Logs in Cloudwatch" in the right hand corner. If you click that link and you should see the errors that are being produced.
You can also use console.log() to log any information being returned from your REST api, which will be logged in cloudwatch and can help you see where your errors are.
This is just a guess from the top of my head. To really help some detailed error message would be required like mentioned about.
But just a guess: Your http.request() is using the http module (https://nodejs.org/api/http.html) and your are accessing the a https resource. If so there is a https (https://nodejs.org/api/https.html) module or use something like axios https://www.npmjs.com/package/axios or requestjs (https://github.com/request/request) this will handle both.
Like I said just a blind guess without detailed error message and seeing your require statements but I am happy to dive deeper if you happen to have details.
HTH
Your callback from the Lambda has to return a valid status code and body. Like this:
let payload = {
statusCode: 400,
body: JSON.stringify('body'),
headers: {"Access-Control-Allow-Origin": "*"}
};
callback(null, payload);
On top of that, to call this from client side code, you have to pass the CORS header back.

How to send a HTTP request from Google Cloud Functions (nodeJS)

This is probably a simple question but I'm new to cloud functions/Node programming and haven't found the right documentation yet.
How do I write a Google cloud function that will receive a HTTP request but then send a HTTP request to a different endpoint? For example, I can send the HTTP trigger to my cloud function (https://us-central1-plugin-check-xxxx.cloudfunctions.net/HelloWorldTest). Later in the project I'll figure out how to implement a delay. But then I want to respond with a new HTTP request to a different endpoint (https://maker.ifttt.com/trigger/arrive/with/key/xxxx). How do I do that?
exports.helloWorld = function helloWorld(req, res) {
// Example input: {"message": "Hello!"}
if (req.body.message === undefined) {
// This is an error case, as "message" is required.
res.status(400).send('No message defined!');
} else {
// Everything is okay.
console.log(req.body.message);
res.status(200).send('Success: ' + req.body.message);
// ??? send a HTTP request to IFTTT endpoint here
}
};
Here is the code that I managed to get working with help from Chetan Kanjani. When I send a text message to my Google Cloud function endpoint, it replys with a text message to IFTTT (a different endpoint).
const request = require('request');
exports.helloWorld = function helloWorld(req, res) {
// Example input: {"message": "Hello!"}
if (req.body.message === undefined) {
// This is an error case, as "message" is required.
res.status(400).send('No message defined!');
} else {
// Everything is okay.
console.log(req.body.message);
request.get('https://maker.ifttt.com/trigger/arrival/with/key/xxxx', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); //Prints the response of the request.
});
res.status(200).send("Success");
}
};
I also had to change the package.json file to include the request package. It already had the sample-http package, I added the dependencies:
{
"name": "sample-http",
"version": "0.0.1",
"dependencies": {
"request": "^2.81.0"
}
}
I'm still not sure where the console.log function prints out the information. That might be helpful for future debugging.
The Request module uses callbacks. If you want to use JavaScript promises instead, the Axios module provides equivalent functionality.
Old, but I came across this while searching myself:
request module with promise support is (request-promise)
The code below worked. Not sure if Axios is the ideal module for simple requests like these, but the Google Cloud Function documentation uses Axios so it seemed sensible to also use Axios. Other answers use the request module, but it was deprecated in February 2020.
Note: GCF doesn't support ES6 natively at this time. ES6 support is coming with Node 13.
Package.json
{
"name": "YOUR_NAME",
"version": "0.0.1",
"dependencies": {
"axios": "^0.19.2"
}
}
Index.js
/**
* Required Modules
*/
const axios = require("axios");
/**
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.run = async(req, res) => {
// Set API end point.
let apiURL = YOUR_URL;
// Wrap API parameters in convenient object.
let apiData = {
PARAM_1: PARAM_DATA,
PARAM_2: PARAM_DATA
};
// Invoke API.
axios.post(apiURL,
JSON.stringify(apiData)
)
.then((response) => {
res.status(200).send(response.data);
console.log(response);
}, (error) => {
res.status(500).send(response.data);
console.log(error);
});
};
Use https://www.npmjs.com/package/request module.
var request = require('request');
request.get('https://maker.ifttt.com/trigger/arrive/with/key/xxxx', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); //Prints the response of the request.
});

Resources