Sending data from API Gateway to Lambda - amazon-web-services

Goal: Get real-time stock data from IEX API, store it in DynamoDB, use data in DynamoDB to display on site.
Edit: I want to use the pull mechanism from the API where I can pull data periodically.
Currently, on API gateway, I created a get method for my stocks resource where I set the integration type to HTTP and entered the IEX Endpoint URL as the Endpoint URL. For now, I just got the data for one stock and the JSON Response Body looks like:
{
"symbol": "AAPL",
"companyName": "Apple Inc",
"primaryExchange": "NASDAQ/NGS (GLOBAL SELECT MARKET)",
"calculationPrice": "close",
"open": 132.5,
"openTime": 1610116201607,
"openSource": "official",
"close": 132.05,
"closeTime": 1610139600449,
"closeSource": "official"
}
I want to integrate Lambda here somehow so that it can get this API data and store it in DynamoDB. So far this is what my Lambda function looks like:
'use strict';
const AWS = require('aws-sdk');
exports.handler = async (event, context) => {
const documentClient = new AWS.DynamoDB.DocumentClient();
let responseBody = "";
let statusCode = 0;
const { symbol, companyName } = JSON.parse(event.body);
const params = {
TableName: "Stocks",
Item: {
symbol: symbol,
companyName: companyName
}
};
try {
const data = await documentClient.put(params).promise();
responseBody = JSON.stringify(data);
statusCode = 201;
} catch(err) {
responseBody = `Unable to put product: ${err}`;
statusCode = 403;
}
const response = {
statusCode: statusCode,
headers: {
"Content-Type": "application/json"
},
body: responseBody
};
return response
};
How do I get the API data from API Gateway and integrate it with a Lambda function that stores this data to DynamoDB?

Related

Lambda used SNS to send SMS but stopped working

I was just having fun in sending me SMS from a Lambda called via API Gateway (REST API). No problem at all until it suddendly stopped sending SMS. I'm actually using a free tier level on my AWS account, but in no way I have reached the maximum sendable SMS limit.
Permissions and roles have not been modified from yesterday when text messages still were arriving to my verified mobile number.
As you can see, inside my code, I used a "test2" variable to return the result for SMS sending but it's barely useless.
Is there any way to better undestand the error behind this problem? And why am I getting it all of a sudden?
My lambda code:
const AWS = require("aws-sdk");
const dynamo = new AWS.DynamoDB.DocumentClient();
const SNS = new AWS.SNS();
const tableName = "Testing";
const smsMessage = {
PhoneNumber: '+39#mynumber#',
Message: 'Someone called your api!'
};
const httpMethodConverter = 'http-method';
const pathRequestConverter = "resource-path";
const headers = {
"Access-Control-Allow-Origin":"https://#myaccount#.github.io",
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Origin, Content-Type, X-Auth-Token"
};
let body;
let statusCode = 200;
let test2;
exports.handler = async (event, context) => {
try {
let test = JSON.stringify(event);
let callContext = event.context;
let httpMethod = callContext[httpMethodConverter];
let path = callContext[pathRequestConverter];
let methodAndPath = httpMethod + " "+ path;
test2= await SNS.publish(smsMessage).promise();
switch (methodAndPath) {
case "DELETE /items/{id}":
await dynamo
.delete({
TableName: tableName,
Key: {
Id: parseInt(JSON.parse(test).params.path.id)
}
})
.promise();
body = `Deleted item ${JSON.parse(test).params.path.id}`;
break;
case "GET /items/{id}":
body = await dynamo
.get({
TableName: tableName,
Key: {
Id: parseInt(JSON.parse(test).params.path.id)
}
})
.promise();
break;
case "GET /items":
body = await dynamo.scan({ TableName: tableName }).promise();
break;
case "POST /items":
var bodyParser = "body-json";
var bodyPassed = JSON.parse(test)[bodyParser];
await dynamo
.put({
TableName: tableName,
Item: {
Id: parseInt(bodyPassed.Id),
Type: bodyPassed.Type
}
})
.promise();
body = "Put item "+ bodyPassed.Type+ " id: " + parseInt(bodyPassed.Id);
break;
default:
throw new Error(`Unsupported route: "${event.context}"`);
}
} catch (err) {
statusCode = 400;
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
test2
};
};
This is the answer for my SNS.publish(message).promise
"test2": {
"ResponseMetadata": {
"RequestId": "b2fbd9fc-4cc0-54e8-a660-82#########"
},
"MessageId": "c94393bf-cbb3-5cb9-8155-c#########"
}
If you enable delivery status logging through e.g. https://docs.aws.amazon.com/sns/latest/dg/sms_stats_cloudwatch.html, you should receive an error message detailing why the message could not be delivered. Most likely, you've hit the default monthly $1 spend limit quota.

AWS - API Gateway - Lambda handles callback

I got "Internal server error" Status: 502 on AWS API Gateway. Searched solutions this post says need to handle callback with a callback function. Would anyone please advise how to incorporate the callback codes with my AWS-Lambda function below? Thank you so much.
message: "Internal server error" when try to access aws gateway api
callback(null, {
statusCode: 200,
body: JSON.stringify(message),
headers: {'Content-Type': 'application/json'}
});
My AWS-Lambda function
'use strict';
const AWS = require('aws-sdk');
exports.handler = async (event, context) => {
const documentClient = new AWS.DynamoDB.documentClient();
let responseBody = "";
let statusCode = 0;
const {
id,
productname
} = JSON.parse(event.body);
const params = {
TableName: "Products",
Item: {
id: id,
productname: productname
}
};
try {
const data = await documentClient.put(params).promise();
responseBody = JSON.stringify(data);
statusCode = 201;
} catch (err) {
responseBody = `Unable to put product: ${err}`;
statusCode = 403;
}
const response = {
statusCode: statusCode,
headers: {
"Content-Type": "application/json"
},
body: responseBody
};
return response
};

AWS API Gatway (Proxy) with Lambda - Thworing internal server error

I am working on a custom auth solution, I backend is on NODE (lambda) and calling that lambda by API gateway (it's a post-call).
For every thin is working fine if I use no-Proxy APIs, but in my case in need to pass custom additional headers. And when I tried with prox it is not responding. (it look like Cognito async call takes time or response is not resolving)
I am not sure I am missing some configuration or something wrong with code (code is working fine individual lambda and with API without Proxy).
here is my Lambda code.
// const AWS = require("aws-sdk");
// var crypto = require("crypto-js");
var CryptoJS = require("crypto-js");
var Crypto = require("crypto");
const { CognitoIdentityServiceProvider } = require("aws-sdk");
const hashSecret = (clientSecret, username, clientId) =>
Crypto.createHmac("SHA256", clientSecret)
.update(username + clientId)
.digest("base64");
async function isUserValid() {
const USER_POOL_ID = "poolid";
const CLIENT_ID = "clidntID";
const CLIENT_SECRET = "secreteCode";
const Password = "userName";
const Username = "password";
const cognito = new CognitoIdentityServiceProvider({
region: "ap-southeast-2",
});
try {
const payload = {
UserPoolId: USER_POOL_ID,
AuthFlow: "ADMIN_NO_SRP_AUTH",
ClientId: CLIENT_ID,
AuthParameters: {
USERNAME: "username",
PASSWORD: "password",
SECRET_HASH: hashSecret(CLIENT_SECRET, Username, CLIENT_ID),
},
};
const response = await cognito.adminInitiateAuth(payload).promise();
// // console.log("respone :", response)
// console.log("before response node js lambda ::: ")
return response;
} catch (e) {
console.log("error : ", e.message);
}
}
async function test() {
return "test ";
}
exports.handler = async (event) => {
// TODO implement
console.log("event : ", event);
'
const response = {
statusCode: 200,
headers: {
"Content-Type" : "application/json",
"Access-Control-Allow-Origin" : "*",
"X-Content-Type-Option" : "nosniff",
"Content-Security-Policy" : "default-src self",
"X-frame-options" : "DENY",
"Cache-Control" : "max-age=86400",
"X-XSS-protection" : 0,
"X-rate-limit": 600,
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
},
// body: await test() // (this response is working fine
body: await isUserValid(),
};
return response;
};
Errors when tested from API gateway with proxy setting on :
{
"message": "Internal server error"
}
Response Headers
{"x-amzn-ErrorType":"InternalServerErrorException"}
I tried multiple options but nothing is working for me.
The 'body' property must be a JSON string.
await cognito.adminInitiateAuth(payload).promise() is returning an object. You need to JSON.stringify() that response. Be sure to take care of the error case , too.

Sever-less AWS Lambda Dynamodb throw internal error

I made one todo app by using lambda. I used sever-less framework for deployment. I made one post request where user can create a todo-list. For testing I am using post-man. For my Lambda function I am using async function. I can able to make post request and my item store in Dynamo db but I got response Internal server error. My goal is show in my postman what I kind of post request I made.
Here is my code:
'use strict'
const AWS = require('aws-sdk');
const uuid = require('uuid');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.createTodo = async (event) => {
const datetime = new Date().toISOString();
const data = JSON.parse(event.body);
const params = {
TableName: 'todos',
Item: {
id: uuid.v1(),
task: data.task,
done: false,
createdAt: datetime,
updatedAt: datetime
}
};
try {
let data = await dynamoDb.put(params).promise();
console.log(data);
return JSON.stringify(data); // this throw me internal server error.
} catch (error) {
console.log(error);
}
};
Since you are calling the Lambda function via API Gateway, you need to convert the response to the following structure -
return {
statusCode: 200,
body: JSON.stringify(data),
// headers: {'Content-Type': 'application/json'}, // Uncomment if needed by your client
}

Unable to perform getobject from aws s3 in aws-lambda

I am new to aws-lambda and aws-s3. I am trying to create one microservice using api-gateway, aws s3 and aws lambda.
I have written lambda function to retrive object from s3, but it sends null and not throwing any error. I am not sure what is going wrong.
I have setup role and gave access to s3 and used that role for lambda
const AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = async (event) => {
var params = {
"Bucket": "bucketname",
"Key": "keyname"
};
s3.getObject(params, function(err, data){
if(err) {
return "error while fetching data";
} else {
return data;
}
});
};
What am I doing wrong here?
You should return the data in the proper response format required for API gateway proxy and use the callback parameter to reply, so change your function to look like this:
const AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = async (event, context, callback) => {
var params = {
"Bucket": "bucketname",
"Key": "keyname"
};
s3.getObject(params, function(err, data){
if(err) {
return callback(new Error("error while fetching data"));
} else {
let response = {
statusCode: 200,
headers: {
"x-custom-header" : "my custom header value"
},
body: JSON.stringify(data)
};
return callback(null, response);
}
});
};
If you're not using API gateway proxy Lambda integration, then you can simply change the response to just return callback(null, data);