I am struggling to understand a basic aspect of Lambda implementation.
Problem: how to use a lambda both inside and outside of an API context?
I have a lambda (nodejs) with an API gateway in front of it:
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/myfunction/
Handler: app.lambdaHandler
Runtime: nodejs14.x
Timeout: 4
Policies:
- DynamoDBCrudPolicy:
TableName: MyTable
Events:
ApiEvent:
Type: Api
Properties:
Path: /myfunc
Method: any
The handler is used to read (GET) or write (POST) into a a DynamoDB table and returns accordingly. If no method is passed it assumes GET.
exports.lambdaHandler = async (event) => {
const method = event.httpMethod ? event.httpMethod.toUpperCase() : "GET";
try {
switch (method) {
case "GET":
// assuming an API context event.queryStringParameters might have request params. If not the parameters will be on the event
const params = event.queryStringParameters ? event.queryStringParameters : event;
// read from dynamo db table then return an API response. what if outside an API context?
return {
statusCode: 200,
body: JSON.stringify({ message: "..." })
};
case "POST":
// similarly the body will be defined in an API context
const body = typeof event.body === "string" ? JSON.parse(event.body) : event.body;
// write to dynamo db table
return {
statusCode: 200,
body: JSON.stringify({ message: "..." })
};
default:
return {
statusCode: 400,
body: JSON.stringify({ error: "method not supported" })
};
}
} catch (error) {
// this should throw an Error outside an API context
return {
statusCode: 400,
body: JSON.stringify({ error: `${typeof error === "string" ? error : JSON.stringify(error)}` })
};
}
}
Is there an easy way to refactor this code to support both scenarios? For example a step function could call this lambda as well. I know I can have the step function invoking an API but I think this is overkill as step functions support invoking lambdas directly.
I see 2 ways I can go about this:
The lambda has to be aware of whether it is being invoked within an API context or not. It needs to check if there's a http method, queryStringParameters and build its input from these. Then it needs to return a response accordingly as well. A stringified JSON with statusCode or something else, including throwing an Error if outside an API call.
The lambda assumes it is being called from an API. Then the step function needs to format the input to simulate the API call. The problem is that the response will be a string which makes it difficult to process inside a step function. For example assigning it to a ResultPath or trying to decide if there was an error or not inside a choice.
Additionally I could have the step function calling an API directly or the last resort would be to have 2 separate lambdas where the API lambda calls the other one but this will incur additional costs.
Thoughts? Thanks.