My Lambda function in node.js:
console.log('Loading function');
exports.handler = function(event, context) {
console.log('value1 =', event.key1);
context.succeed("Hello " + event.key1);
};
I want a client (my laptop) to send an object that contains the value "world" to this lambda function. The function adds "Hello " and returns "Hello world".
I used cmd with curl with the following statement:
curl -X POST -d '{"key1":"world"}' https://blablablabla.execute-api.us-west-2.amazonaws.com/prod/helloworld2
But I only get back {"message":"internal server error"}
Any ideas? Are there any other ways to send the "world" value. Maybe javascript in a html file or a simple java app in Eclipse? The lambda function itself is fine. I successfully tested it with a test event.
Your function seems fine. But you are missing the Content-Type header on your cURL command. Do it as follows:
curl -H "Content-Type: application/json" -X POST -d "{\"key1\": \"World\"}" https://blablablabla.execute-api.us-west-2.amazonaws.com/prod/helloworld2
You can double check this requirement in this AWS documentation.
Update: Try with this function (I only added the callback parameter)
'use strict';
console.log('Loading function');
exports.handler = function(event, context, callback) {
console.log('value1 =', event.key1);
callback(null, {"Hello": event.key1});
};
Related
I am trying to get some data via Webhook into lambda function using API Gateway and SQS. This Webhook contains a JSON payload, and HTTP headers that provide context. Since there is no way to get these webhook HTTP headers from API Gateway to SQS using "Action=SendMessage" in Mapping template (correct me if my assumption is wrong...I have tried http headers in method request and integration request), I have included the headers from webhook in the API Gateway mapping template as follows:
Action=SendMessage&MessageGroupId=$input.params('MessageGroupId')&
MessageBody={
"Header1":"$input.params('Header1 key')",
"body":"$input.json('$')"
}
My code in Lambda function is as follows:
'use strict';
exports.handler = async function(event, context) {
if (event.Records) {
event.Records.forEach(record => {
var rec = JSON.parse(JSON.stringify(record.body));
console.log("Record body: " + rec);
console.log("Header1: " + rec.Header1);
});
}
return {};
};
The value of 'rec' in CloudWatch log is rather quite long but here is the simplified version:
Record body: {
"Header1":" OYqmDnuUpDs8oF1RwoBnJywBY6c1I4qLklU=",
"body":"{"id":820982911946154508,"email":"jon#doe.ca","closed_at":null,"created_at":"2020-11-30T20:25:43-05:00","updated_at":"2020-11-30T20:25:43-05:00","number":234,"note":null,"token":"123456abcd","gateway":null,"test":true,"total_price":"7.00","subtotal_price":"-3.00"
}
My question - how can I read the values of Header1 and body? I have tried rec.Header1, rec[0].Header1 and rec["Header1"] etc. and I get "Undefined" in all the cases. Thanks.
The body is already stringified.
You need to simply call JSON.parse(record.body) to parse the string to valid JSON. Note that this could throw an error.
Describe the issue
I'm not really sure if this is an Axios issue or not. The following code runs successfully on my local development machine but always time out whenever I run it from the cloud (e.g. AWS Lambda). Same thing happens when I run on repl.it.
I can confirm that AWS Lambda has internet access and it works for any other API but this:
https://www.target.com.au/ws-api/v1/target/products/search?category=W95362
Example Code
https://repl.it/repls/AdeptFluidSpreadsheet
const axios = require('axios');
const handler = async () => {
const url = 'https://www.target.com.au/ws-api/v1/target/products/search?category=W95362';
const response = await axios.get(url, { timeout: 10000 });
console.log(response.data.data.productDataList);
}
handler();
Environment
Axios Version: 0.19.2
Runtime: nodejs12x
Update 1
I tried the native require('https') and it times out on both localhost and cloud server. Please find sample code here: https://repl.it/repls/TerribleViolentVolume
const https = require('https');
const url = 'https://www.target.com.au/ws-api/v1/target/products/search?category=W95362';
https.get(url, res => {
var body = '';
res.on('data', chunk => {
body += chunk;
});
res.on('end', () => {
var response = JSON.parse(body);
console.log("Got a response: ", response);
});
}).on('error', e => {
console.log("Got an error: ", e);
});
Again, I can confirm that same code works on any other API.
Update 2
I suspect that this is something server side as it also behaves very weirdly with curl.
curl from local -> 403 access denied
curl from local with User-Agent header -> success
curl from cloud server -> 403 access denied
It must be server side validation, something related to AkamaiGHost.
You have probably placed your Lambda function in a VPC without Internet access to the outside world. Try check the VPC section in your lambda configuration, and setup an internet gateway accordingly
You should try by wrapping axios call into try/catch maybe that will catch the issue.
const axios = require('axios');
const handler = async () => {
try {
const url = 'https://www.target.com.au/ws-api/v1/target/products/search?category=W95362';
const response = await axios.get(url, { timeout: 10000 });
console.log(typeof (response));
console.log(response);
} catch (e) {
console.log(e, "error api call");
}
}
handler();
As suggested by Akshay you can use try and catch block to get the error. Maybe it helps you out.
Have you configured Error Handling for Asynchronous Invocation?
To configure error handling follow the below steps:
Open the Lambda console Functions page.
Choose a function.
Under Asynchronous invocation, choose Edit.
Configure the following settings.
Maximum age of event – The maximum amount of time Lambda retains an event in the asynchronous event queue, up to 6 hours.
Retry attempts – The number of times Lambda retries when the function returns an error, between 0 and 2.
Choose Save.
axios is only Promise based HTTP client for the browser and node.js and as you set timeout: 10000 so I believe timeout issue is not from its end.
Although your API
https://www.target.com.au/ws-api/v1/target/products/search?category=W95362
is working fine on the browser and rendering JSON data.
and Function timeout of lambda is by default 15 minutes, which I believe is enough for the response. There may be another issue.
Make sure you have set other configurations like permissions etc. as suggested in the documentation.
Here you can check the default limits for AWS lambda.
I know the request param in a firebase https.onRequest corresponds to a Express response.
I want to run the cloud function using this format (local testing):
http://localhost:5000/test-2c6e8/us-central1/coins?userid=1
So, now from the cloud function I just want to get the userId param. The test function I have written is:
exports.coins = functions.https.onRequest((request, response) =>
{
var db = admin.firestore();
response.json({query: JSON.stringify(request.query),
params: JSON.stringify(request.params),
body: JSON.stringify(request.body)});
response.end();
});
and this is the output I get:
query "{}"
params "{\"0\":\"\"}"
body "{}"
I have tried multiple things without any luck. Why is this happening?
Short answer is req.query.name_of_the_parameter; for the long answer, you can read here.
This question already has answers here:
AWS API Gateway base64Decode produces garbled binary?
(3 answers)
Closed 6 years ago.
I'm trying to set up a Lambda and API Gateway that will do a s3.getObject() and output the binary image as a response. Eventually I'd like to pull an image from s3 and resize on the fly instead of saving them back to s3, however I can't seem to get even a simple image to output.
My simple lambda looks like this:
'use strict';
const http = require('http');
exports.handler = (event, context, callback) => {
http.get('http://i.stack.imgur.com/PIFN0.jpg', function(res) {
var body = '';
res.on('data', function(chunk) {
// Agregates chunks
body += chunk;
});
res.on('end', function() {
callback(null, body);
});
});
};
I've set the API Gateway Binary Support to allow 'image/jpeg' and I've tried setting the Content Type in the Method Response and Integration Response.
Method Response:
Integration Response:
I found my answer here: AWS Gateway API base64Decode produces garbled binary?
It requires a CLI command to change a setting that isn't exposed in the AWS Console when you select Lambda Function on the Create Method screen.
Did you read this blog post?
Please follow those instructions and ensure your client is correctly sending the Content-Type and Accept headers
I used Parse's CLI with the new Heroku integration to create the scaffold NodeJS project (parse new).
The example cloud function it gives you is:
// Hello
Parse.Cloud.define('hello', function(request, response) {
response.success('Hello world! ' + (request.params.a + request.params.b));
});
I can hit this route with the following CURL command and everything works fine:
curl -X POST \
-H "X-Parse-Application-Id: b8qPYS4SLSz0WoSWXlWeQosmF2jJPUPydetg3esR" \
-H "X-Parse-REST-API-Key: TOJLbfbNXSQcBdDVnU0MnKVu7SyamQvZmorHL5iD" \
-H "Content-Type: application/json" \
-d '{"a": "Adventurous ", "b": "Parser"}' \
https://api.parse.com/1/functions/hello
But then I added a new Class to my Parse Data, inserted a row, and tried to query & return the results. I keep getting {"code":143,"error":"Invalid webhook response status: 500 Internal Server Error"} as the response.
I'm fairly certain it is not my code that is the problem and am guessing there is some configuration step or something I'm missing.
Here is my modified Parse function:
// Hello
Parse.Cloud.define('hello', function(request, response) {
var query = Parse.Query("Favorites");
query.find({ useMasterKey: true }).then(
function(results) {
response.success('win');
}, function() {
response.error('fail');
});
});
And a picture of my Parse Class with the inserted row:
I have Googled the error and can't find any good answers only poorly worded questions. I'm completely at a loss here. Thanks in advance for your help.
Looks like Parse is wrong initialised on register-webhooks.js post deploy script:
Parse.initialize(process.env.PARSE_APP_ID, "unused", process.env.PARSE_MASTER_KEY);
And without second parameter (JavaScript Key) you can't execute any Parse.Query from cloud functions.
So my solution is:
Add new PARSE_JS_KEY to Heroku Config Variables (value is JavaScript Key from Parse->Settings->Keys)
In server.js file add line:
Parse.initialize(process.env.PARSE_APP_ID, process.env.PARSE_JS_KEY, process.env.PARSE_MASTER_KEY);
before require('./cloud/main.js');
PS: Place process.env.PARSE_JS_KEY directly in register-webhooks.js initializer does not work.