I have multiple AWS stacks where, among other things, I create AWS Lambdas and API Gateway endpoints, let's consider this stack the lambda_unified_crud_stack and a second one called lambda_other_crud_stack (lambda_other_crud_stack is run first)
When, in the same stack, lambda_unified_crud_stack, I'm creating a Lambda, and for that Lamba, I create an API Gateway resource with a stage variable everything works without any issue. The endpoint is created where the Lambda with the stage variable in the integration request, something like TestLambda:${stageVariables.lambdaAlias}
. I achieved this by doing the following using the CDK.
TestLambda = lambda_.Function(
self,
"my_lambda",
function_name="TestLambda",
description="A Lambda to test permissions",
code=lambda_code,
memory_size=512,
handler="my_lambda.main",
runtime=lambda_.Runtime.PYTHON_3_9,
timeout=Duration.minutes(1),
)
#get_gateway() is custom code to the the API
api = get_gateway(self.scope, gateway_name)
root = api.root
lambdaArn = TestLambda.function_arn + ":${stageVariables.lambdaAlias}"
integration = aws_apigateway.LambdaIntegration(lambdaArn)
endpoint = root.resource_for_path("/test_lambda_api/").add_method("GET", integration)
Doing this I create the API Gateway resource, where the Integration request is a lambda referencing a stage variable, without a problem.
But in other cases I need to get a Lamdba that was previously created in the lambda_other_crud_stack, to use in this stack so that I can create the endpoint for it, in that case, I do the following.
other_stack_lambda_arn_ = f"arn:aws:lambda:{self.region}:{self.account_id}:function:OtherStackLambd"
OtherStackLambda= aws_lambda.Function.from_function_arn(self.scope, id=f"Role{lambda_arn_}", function_arn = other_stack_lambda_arn_ )
#get_gateway() is custom code to the the API
api = get_gateway(self.scope, gateway_name)
root = api.root
other_lambdaArn = OtherStackLambda.function_arn + ":${stageVariables.lambdaAlias}"
other_integration = aws_apigateway.LambdaIntegration(other_lambdaArn)
endpoint = root.resource_for_path("/test_lambda_api/other_lambda").add_method("GET", other_integration )
And when I run this in CDK, I get the error:
[#/FunctionName: string [arn:aws:lambda:eu-west-1:668526471736:function:OtherStackLambd:${stageVariables.lambdaAlias}] does not match pattern ^(arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$]
, when I was expecting for this to create the endpoint like in the other case.
When I'm doing the same thing, but without referencing a stage variable (meaning without doing this other_lambdaArn = OtherStackLambda.function_arn + ":${stageVariables.lambdaAlias}") using aws_lambda.Function.from_function_arn() works without any problem.
I found this issue on Github: https://github.com/aws/aws-cdk/issues/23296, and tried to use fromFunctionAttributes()
, instead of `lambda_from_arn(), but it still did not work.
A possible fix would be to create all the AWS Lambdas and the respecting API Gateway endpoints always in the same stack, but that would not work, because, due to company policies, I need to keep everything organized in the best way possible (for example, all the AWS Lambdas related to DynamoDB in a stack, and all the AWS Lambda related to Neptune in another)
UPDATE: Got it working, and now the CDK is behaving like we were expecting, what we do is the following:
For creating endpoint resources using Lambdas that are created in the same stack we keep things basically the same, just some minor changes:
TestLambda = lambda_.Function(
self,
"my_lambda",
function_name="TestLambda",
description="A Lambda to test permissions",
code=lambda_code,
memory_size=512,
handler="my_lambda.main",
runtime=lambda_.Runtime.PYTHON_3_9,
timeout=Duration.minutes(1),
)
#get_gateway() is custom code to the the API
api = get_gateway(self.scope, gateway_name)
root = api.root
lambdaArn = TestLambda.function_arn + ":${stageVariables.lambdaAlias}"
lambda_function =aws_lambda.Function.from_function_arn(self.scope,f'lambda_integration_request_{lambdaArn}' ,lambdaArn)
integration = aws_apigateway.LambdaIntegration(lambda_function, allow_test_invoke=False)
endpoint = root.resource_for_path("/test_lambda_api/").add_method("GET", integration)
But for the case where I'm trying to use a Lambda that was created from another stack to create a API Gateway resource, I'm doing it like this
# The Lambda name in this case is OtherStackLambd
other_stack_lambda_arn_ = f"arn:aws:lambda:{self.region}:{self.account_id}:function:OtherStackLambd"
#get_gateway() is custom code to the the API
api = get_gateway(self.scope, gateway_name)
root = api.root
other_lambdaArn = OtherStackLambda.function_arn + ":${stageVariables.lambdaAlias}"
integration = aws_apigateway.AwsIntegration(
service='lambda',
path=f'2015-03-31/functions/{lambdaArn}/invocations',
region=self.region,
proxy=True,
options=aws_apigateway.LambdaIntegrationOptions(allow_test_invoke=False)
)
endpoint = root.resource_for_path("/test_lambda_api/other_lambda").add_method("GET", other_integration )
And doing this works, everything works fine. BUT I fell this isn't a great solution, because in the CDK documentation, it specifically says that AwsIntegration is intended for calling all AWS service actions, but is not recommended for calling a Lambda function, because the Lambda custom integration is a legacy technology.
So everything works, but I'm doing something the documentation directly tells me isn't recommended