How do I get response headers for AWS JavaScript SDK calls? - amazon-web-services

I have a simple AWS Lambda function which makes an S3.getObject() call as follows:
const AWS = require('aws-sdk');
AWS.config.logger = console;
const s3 = new AWS.S3();
exports.handler = async (event) => {
return await getObject({
Bucket: "<MY-BUCKET>",
Key: "<MY-KEY>"
}).then( (res) => {
console.log('Retrieved object from S3');
console.log(res);
return res.Body.toString('ascii');
})
};
async function getObject(params){
return await s3.getObject(params).promise();
}
I've enabled logging SDK calls as per this document.
How do I get response headers for the s3.getObject() SDK call that was made? I am basically trying to retrieve the S3 request ID and extended request ID.
The in-built logger added via the "AWS.config.logger = console;" line does not seem to log response headers. How else do I get response headers for AWS JavaScript SDK calls?
P.S: Bonus points if you can let me know whether or not I need two await keywords in the code above.

Listen to httpHeaders event.
var requestObject = s3.getObject(params);
requestObject.on('httpHeaders', (statusCode, headers, response, statusMessage) => {
// your code here.
});
requestObject.promise()
.then(response => { ... })

Related

How to write data from an external API to DynamoDB?

I want to get real-time data from a stock API (IEX API) and load it to DynamoDB. Most of the tutorials I've watched so far (like this around 15:10) show how to create Lambda functions and integrate with API gateway. However, they are still manually entering the data to load to the table. How do I use the API Gateway and Lambda to get data from the IEX API and load it to DynamoDB rather than writing the data myself?
Following some tutorials, my Lambda function for loading data to the table is:
const AWS = require('aws-sdk');
exports.handler = async (event, context) => {
const documentClient = new AWS.DynamoDB.DocumentClient();
let responseBody = "";
let statusCode = 0;
const { id, stocksymbol} = JSON.parse(event.body);
const params = {
TableName: "StockData",
Item: {
id: id,
stocksymbol: stocksymbol
}
};
try {
const data = await documentClient.put(params).promise();
responseBody = JSON.stringify(data);
statusCode = 201;
} catch(err) {
responseBody = `Unable to put item: ${err}`;
statusCode = 403;
}
const response = {
statusCode: statusCode,
headers: {
"Content-Type": "application/json"
},
body: responseBody
};
return response
};
I would be getting more data from the API (opening price, closing price etc.) but this is what I have for now.
Assuming you need to utilize pull mechanism (you need to get data from API yourself), you can use AWS EventBridge rule to trigger your lambda periodically with interval of your preference - https://docs.aws.amazon.com/eventbridge/latest/userguide/create-eventbridge-scheduled-rule.html. In lambda you download the API data and store them in DynamoDb.
If you can use push mechanism (you can get data pushed to you, e.g. https://iexcloud.io/docs/api/?gclid=CjwKCAiA_9r_BRBZEiwAHZ_v17o9kJuPyF5Do_E3_mwC0uHEh2yXqqOdtVgqvc34yEk5RR8W8028HRoC0HUQAvD_BwE#webhooks), you can set the your API gateway resource URL as a target path, while having your lambda function as the handler for the API Gateway resource URL, storing the pushed data to the DynamoDb.

Lambda writes to DynamoDb on Test Event but not when Triggered with CloudFront

I want to save every request to my S3 object in DynamoDB.
This is my pipeline.
I'm deploying the function to Lambda#Edge with viewer-response as the trigger and just to make sure that the function runs I'm also inserting a custom header with the image served. The header is coming as expected hence the function runs.
When I test this function via the Lambda Console, it is inserting the entry in DynamoDB. The problem is that while it's returning the custom header, it's not making a DB entry when I go to the CloudFront CDN URL.
For example when I goto https://d********e.cloudfront.net/test-image.png it should -
Serve the Respective Image (Working Properly)
Have the custom header (Working Properly)
Store entry in DynamoDB (Not working)
Here's the code for reference. Please note that the function is storing an entry in DB while running a test event in Lambda Console and I want this function to run every time the CDN serves an image.
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const shortid = require('shortid');
module.exports.image = async (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
headers['mycustomheader'] = [{ key: 'My-Custom-Header', value: new Date().getTime().toString() }];
await storeClickEvent(event);
callback(null, response);
};
const storeClickEvent = async (data) => {
const params = {
TableName: 'my-dummy-table-name',
Item: {
event: data,
id: shortid.generate(),
createdAt: new Date().getTime(),
}
};
try {
await dynamoDb.put(params).promise();
} catch (err) {
console.error('Error occurred =>', err);
}
}

Cannot find module aws-amplify, lambda function

I'm try to make an API post request in my lambda function but in the aws website, using nodejs I cannot import API ? Here is what I am trying
console.log('Loading function');
const AWS = require('aws-sdk');
const translate = new AWS.Translate({ apiVersion: '2017-07-01' });
var API = require('aws-amplify');
exports.handler = async (event, context) => {
try {
const params = {
SourceLanguageCode: 'en', /* required */
TargetLanguageCode: 'es', /* required */
Text: 'Hello World', /* required */
};
const data = await translate.translateText(params).promise();
createSite(data.TranslatedText);
} catch (err) {
console.log(err, err.stack);
}
function createSite(site) {
return API.post("sites", "/sites", {
body: site
});
}
};
I have also tried import...
I think you may be looking at front-end browser based JavaScript examples, which aren't always going to work in a back-end AWS Lambda NodeJS runtime environment. It appears you are trying to use this library, which states it is "a JavaScript library for frontend and mobile developers", which probably isn't what you want to use on AWS Lambda. It appears you also did not include that library in your AWS Lambda function's deployment.
I suggest using the AWS Amplify client in the AWS SDK for NodeJS which is automatically included in your Lambda function's runtime environment. You would create an Amplify client like so:
var amplify = new AWS.Amplify();

How to include a custom header using AWS SDK with SQS Service?

I am using the AWS SDK SQS (with Nodejs) behind a router, to get through the router I need to include a custom header in the REQUEST.
I've seen this documentation (https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html#build-event) that talks about the .on ('build') event in REQUEST:
var req = s3.putObject(params);
req.on('build', function() {
req.httpRequest.headers['Custom-Header'] = 'value';
});
req.send(function(err, data) { ... });
However, using the SQS service is not working, no error has been thrown and the custom header is not included in the REQUEST.
Is it possible include a custom header using AWS SDK with SQS service ?
How make to make this work?
After help, I was able to send messages to the queue with a custom header, below the sample code:
var sqs = new aws.SQS({http_wire_trace: true});
var params = {
MessageBody: 'Hello world!',
QueueUrl: queueUrl,
DelaySeconds: 0
};
var req = sqs.sendMessage(params);
req.on('build', () => {
req.httpRequest.headers['Custom-Header'] = 'bar';
});
req.on('success', (resp) => {
console.log(resp.request.httpRequest.headers)
});
req.send();

s3 list objects return null with sdk

I have a lambda function with has a role with Admin access. I have a S3 bucket and I want to test listing of its contents. Here is the code
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = async (event) => {
var params = { Bucket: 'test-bucket-mine' };
let result = await s3.listObjectsV2(params);
console.log(result);
};
However, the console log looks like the following.
Response:
null
I am testing using lambda test with basic event. Please let me know where I am doing it wrong.
You are awaiting the request object. The request is never being fired. Try:
let result = await s3.listObjectsV2(params).promise();
This will start the request and return a promise that resolves when the request completes. You will then await the result of that promise.