Trigger a lambda function after a rest api is accessed - amazon-web-services

I have a rest API in aws api gateway that access's an external http endpoint and returns some data.
Every time this rest api is accessed and returns data, i need to trigger a lambda function that uses the data returned by the rest api. How can i achieve that ?
Tried looking for answers on this and all of them point to how to trigger a lambda function using a rest api.

You can do this in 2 ways.
When a request is sent to api gateway, invoke a lambda, inside this lambda access your external http endpoint and whatever the result comes, invoke another lambda.
something like this.
const invoke = async (funcName, payload) => {
const client = createClientForDefaultRegion(LambdaClient);
const command = new InvokeCommand({
FunctionName: funcName,
Payload: JSON.stringify(payload),
LogType: LogType.Tail,
});
const { Payload, LogResult } = await client.send(command);
const result = Buffer.from(Payload).toString();
const logs = Buffer.from(LogResult, "base64").toString();
return { logs, result };
};
Use stepfunctions with api gateway ( which would be similar to 1st operation)

Related

How should I implement my lambda handler with my REST API gateway model using non- proxy lambda?

I am stuck on how I should begin my lambda handler that will read some data from dynamodb. I have defined my api gateway model with the requests and response models, therefore do I need to state any status codes in the lambda handler ? Do I use API gateway proxy response event ? Any code examples
in Java would be helpful.
My notes on what I should include in the lambda handler:
access DB
map over table
Find attribute
Return response to api ?
What am I missing ? Thank you.
If you decided to use a non-proxy Lambda integration then you need to define an integration response using a regex. Here is an example using nodeJS:
lambda regex
Normally i declare my error messages just like this:
const errorMessages = {
INTERNAL_SERVER_ERROR: {
message: "Internal server error!",
code: 500
},
ERROR_BODY_INVALID: {
message: "Invalid request body",
code: 400
}
};
Then throw an error like this
exports.handler = function(event, context, callback) {
try {
// do something
} catch (error) {
callback(JSON.stringify(errorMessages.INTERNAL_SERVER_ERROR));
};
}
When a lambda error regex matches then it's mapped to the configured response status code.
P.D. If you are using Java this method does not work and you need to use proxy integration

How to invoke Nodejs lambda from Java based Lambda in AWS

I was trying to invoke Nodejs based lambda from Java-Based lambda. It is invoking the lambda but the payload is not being sent to Nodejs based lambda.
Here is the code for both lambdas:
Nodejs based lambda:
module.exports.handler = async (event, context, callback) => {
console.log('event ', event) // Payload not coming here either event or context
console.log('context', context)
const body = JSON.parse(event);
//Processing and return response
}
Java-based lambda:
AWSLambda client = AWSLambdaClient.builder().withRegion(region).build();
InvokeRequest().withFunctionName("nodejslambda").withPayload(payload);
InvokeResult result = client.invoke(req);
Your help would be greatly appricated.
You must provide additional information like
Are you able to see the node function invoked and what is the response body when you call the invoke method.
Check the node lambda logs if you see the function invoked.
Try to test the function on the console by sending the same payload as test.

API Gateway configuration to receive correct POST body as JSON

I am struggling with getting Lambda + API gateway working well.
This is my code-
exports.handler = async (event) => {
console.log("EVENT -> ", event.body)
let buff = new Buffer(event.body, 'base64');
let text = buff.toString('UTF-8');
console.log("TEXT -> ",text)
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
I have referred to this answer, but, I don't see Integration Request in API Gateway.
What has to be done to get a proper JSON? I know I can use 3rd party npm libs. But, I prefer some fix at AWS end. I just want to use event.body which should return a JSON.
I will re-intepret your question the way I understand It.
1/ You created a Lambda function, connected to a API gateway
2/ You sent an some data to the Lambda function using API gateway
3/ API gateway invoke your function with some data
4/ The data you received inside your Lambda function is neither lost nor corrupted. It is received inside Lambda as the Base64-Encoded format
5/ You do not want to receive the data in Lambda as Base64-Encoded, You do not want to do a step of decoding like you did
let buff = new Buffer(event.body, 'base64');
let text = buff.toString('UTF-8');
If that is the case, you need to take a look at this
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings-workflow.html
First, check what Content-Type header your request are sending.
Then, see if the data you sent to API gateway is actually textual data
Also, go to your API Gateway -> Setting -> Binary Media Types to see if any data type are specifically to be treated as Binary by API Gateway

Programmatically invoke a specific endpoint of a webservice hosted on AWS Lambda

I have a multi-endpoint webservice written in Flask and running on API Gateway and Lambda thanks to Zappa.
I have a second, very tiny, lambda, written in Node, that periodically hits one of the webservice endpoints. I do this by configuring the little lambda to have Internet access then use Node's https.request with these options:
const options = {
hostname: 'XXXXXXXXXX.execute-api.us-east-1.amazonaws.com',
port: 443,
path: '/path/to/my/endpoint',
method: 'POST',
headers: {
'Authorization': `Bearer ${s3cretN0tSt0r3d1nTheC0de}`,
}
};
and this works beautifully. But now I am wondering whether I should instead make the little lambda invoke the API endpoint directly using the AWS SDK. I have seen other S.O. questions on invoking lambdas from lambdas but I did not see any examples where the target lambda was a multi-endpoint webservice. All the examples I found used new AWS.Lambda({...}) and then called invokeFunction with params.
Is there a way to pass, say, an event to the target lambda which contained the path of the specific endpoint I want to call? (and the auth headers, etc.) * * * * OR * * * * is this just a really dumb idea, given that I have working code already? My thinking is that a direct SDK lambda invocation might (is this true?) bypass API Gateway and be cheaper, BUT, hitting the endpoint directly via API Gateway is better for logging. And since the periodic lambda runs once a day, it's probably free anyway.
If what I have now is best, that's a fine answer. A lambda invocation answer would be cool too, since I've not been able to find a good example in which the target lambda had multiple https endpoints.
You can invoke the Lambda function directly using the invoke method in AWS SDK.
var params = {
ClientContext: "MyApp",
FunctionName: "MyFunction",
InvocationType: "Event",
LogType: "Tail",
Payload: <Binary String>,
Qualifier: "1"
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
/*
data = {
FunctionError: "",
LogResult: "",
Payload: <Binary String>,
StatusCode: 123
}
*/
});
Refer the AWS JavaScript SDK lambda.invoke method for more details.

Invoke AWS Lambda and return response to API Gateway asyncronously

My use case is such that I'll have an AWS Lambda front ended with API Gateway.
My requirement is that once the Lambda is invoked it should return a 200 OK response back to API Gateway which get forwards this to the caller.
And then the Lambda should start its actual processing of the payload.
The reason for this is that the API Gateway caller service expects a response within 10 seconds else it times out. So I want to give the response before I start with the processing.
Is this possible?
With API Gateway's "Lambda Function" integration type, you can't do this with a single Lambda function -- that interface is specifically designed to be synchronous. The workaround, if you want to use the Lambda Function integration type is for the synchronous Lambda function, invoked by the gateway, to invoke a second, asynchronous, Lambda function through the Lambda API.
However, asynchronous invocations are possible without the workaround, using an AWS Service Proxy integration instead of a Lambda Function integration.
If your API makes only synchronous calls to Lambda functions in the back end, you should use the Lambda Function integration type. [...]
If your API makes asynchronous calls to Lambda functions, you must use the AWS Service Proxy integration type described in this section. The instructions apply to requests for synchronous Lambda function invocations as well. For the asynchronous invocation, you must explicitly add the X-Amz-Invocation-Type:Event header to the integration request.
http://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-lambda.html
Yes, simply create two Lambda functions. The first Lambda function will be called by the API Gateway and will simply invoke the second Lambda function and then immediately return successfully so that the API Gateway can respond with an HTTP 200 to the client. The second Lambda function will then take as long as long as it needs to complete.
If anyone is interested, here is the code you can use to do the two lambdas approach. The code below is the first lambda that you should setup which would then call the second, longer running, lambda. It takes well under a second to execute.
const Lambda = new (require('aws-sdk')).Lambda();
/**
* Note: Step Functions, which are called out in many answers online, do NOT actually work in this case. The reason
* being that if you use Sequential or even Parallel steps they both require everything to complete before a response
* is sent. That means that this one will execute quickly but Step Functions will still wait on the other one to
* complete, thus defeating the purpose.
*
* #param {Object} event The Event from Lambda
*/
exports.handler = async (event) => {
let params = {
FunctionName: "<YOUR FUNCTION NAME OR ARN>",
InvocationType: "Event", // <--- This is KEY as it tells Lambda to start execution but immediately return / not wait.
Payload: JSON.stringify( event )
};
// we have to wait for it to at least be submitted. Otherwise Lambda runs too fast and will return before
// the Lambda can be submitted to the backend queue for execution
await new Promise((resolve, reject) => {
Lambda.invoke(params, function(err, data) {
if (err) {
reject(err, err.stack);
}
else {
resolve('Lambda invoked: '+data) ;
}
});
});
// Always return 200 not matter what
return {
statusCode : 200,
body: "Event Handled"
};
};
Check the answer here on how to set up an Async Invoke to the Lambda function. This will return 200 immediately to the client, but the Lambda will process on it's own asynchronously.
https://stackoverflow.com/a/40982649/5679071