I am working on a cdk deploy script and I have it somewhat working but am lost/not having luck setting the different stages and applying different lambdas to the api resources.
So I have
// Construct lambdas - prod
const lambdaBacklogGet = new lambdajs.NodejsFunction(this, "name", {
nodeModules: ['axios'],
entry: './src/path/index.js',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_12_X,
timeout: cdk.Duration.seconds(20),
role: webformRole
});
// Construct lambdas - dev
const devLambdaBacklogGet = new lambdajs.NodejsFunction(this, "name-dev", {
nodeModules: ['axios'],
entry: './src/path/index.js',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_12_X,
timeout: cdk.Duration.seconds(20),
role: webformRole
});
// then I Construct API
const api = new apiGateway.RestApi(this, "name-api", {
defaultCorsPreflightOptions: {
allowOrigins: apiGateway.Cors.ALL_ORIGINS,
allowHeaders: apiGateway.Cors.DEFAULT_HEADERS,
allowMethods: apiGateway.Cors.ALL_METHODS,
},
description: "API for Something",
deploy: true,
});
// Default response parameters, to allow CORS
const corsResponseParams = {
"method.response.header.Access-Control-Allow-Origin": true,
};
const corsIntegrationResponseParams = {
"method.response.header.Access-Control-Allow-Origin": "'*'",
};
// REST API - /adding prod endpoint
const backlogResourceAPI = api.root.addResource("backlog");
const issuesBacklogGetIntegration = new apiGateway.LambdaIntegration(lambdaBacklogGet, {});
backlogResourceAPI.addMethod("GET", issuesBacklogGetIntegration, {});
//at the end I do this
// Then create an explicit Deployment construct
const deployment = new apiGateway.Deployment(this, 'my_deployment', { api });
// And different stages
const [devStage, testStage, prodStage] = ['dev', 'test'].map(item =>
new apiGateway.Stage(this, `${item}_stage`, { deployment, stageName: item }));
//api.deploymentStage = prodStage
api.deploymentStage = devStage
the last part I know isn't setup correctly. But basically I want one API Gateway and I want the prod/dev stages to have identical resources/structure. However prod stage should pull specific prod lambdas and dev should call dev lambdas.
Is there any way to set that up through the CDK?
Thanks, Tim
Open the Functions page of the Lambda console. Choose a function and then choose Versions. On the versions configuration page, choose Publish new version. (Optional) Enter a version description.
Steps to create a Lambda Function in AWS CDKStep 1: Instantiate Function Class. Step 2: Add the code for the Lambda Function. Step 3: Adding IAM Permissions for Lambda Function. Step 4: Deploy the Function.
You can have multiple functions in a single class. It's just that you have to set the required function as a handler for a particular API gateway on AWS which you are using it for the lambda function that you created.
Summary. There are three common ways to edit Lambda functions: in the Lambda console, Cloud 9, and locally. There are advantages and disadvantages of all three methods, but personally I think the best choice is to write the function locally and deploy it using a deployment script.
While it is possible to use a Stage Variable
when adding a Lambda integration to an API gateway in the AWS Console it does not seem possible when using CDK at the time of writing this answer.
It is possible to use a Stage Variable
in a path in an S3 integration but for a Lambda integration, the best I could manage was to read the Stage Variables
from the event
and use logic in the Lambda to depending upon which stage was used.
The code for my stack (in Python):
from aws_cdk import core
from aws_cdk import aws_lambda, aws_s3
from my_cdk.api_gateway import ApiGateway
class MyCdkStack(core.Stack):
def __init__(
self,
scope: core.Construct,
construct_id: str,
**kwargs
) -> None:
super().__init__(scope, construct_id, **kwargs)
s3_bucket = aws_s3.Bucket(
self,
"s3_bucket",
bucket_name="dan-dev-so-test-01"
)
default_lambda = aws_lambda.Function(
self,
"default_lambda",
code=aws_lambda.Code.asset("./my_cdk/lambdas/"),
handler="test_lambda.handler",
runtime=aws_lambda.Runtime.PYTHON_3_8,
)
test_lambda = aws_lambda.Function(
self,
"test lambda",
code=aws_lambda.Code.asset("./my_cdk/lambdas/"),
handler="test_lambda.handler",
runtime=aws_lambda.Runtime.PYTHON_3_8,
)
ApiGateway(
self,
"Api Gateway construct",
default_lambda=default_lambda,
test_lambda=test_lambda,
s3_bucket=s3_bucket
)
The code for api_gateway.py
from aws_cdk import core
from aws_cdk import aws_apigateway, aws_lambda, aws_iam, aws_s3
class ApiGateway(core.Construct):
def __init__(
self,
scope: core.Construct,
construct_id: str,
default_lambda: aws_lambda.Function,
test_lambda: aws_lambda.Function,
s3_bucket: aws_s3.Bucket
) -> None:
super().__init__(scope, construct_id)
api = aws_apigateway.LambdaRestApi(
self,
"api",
proxy=False,
handler=default_lambda,
deploy_options=aws_apigateway.StageOptions(
stage_name='v1',
variables={
'stage_name': 'v1'
}
)
)
v2_deployment = aws_apigateway.Deployment(
self,
"deployment2",
api=api,
description="v2"
)
aws_apigateway.Stage(
self,
"stage 2",
deployment=v2_deployment,
stage_name="v2",
variables={
'stage_name': 'v2'
}
)
test_lambda.add_permission(
"permission",
principal=aws_iam.ServicePrincipal('apigateway.amazonaws.com'),
source_arn=api.arn_for_execute_api(
stage='v2', method='GET', path='/lambdas'
)
)
lambda_endpoint = api.root.add_resource("lambdas")
s3_endpoint = api.root.add_resource("test_s3")
lambda_endpoint.add_method(
"GET",
aws_apigateway.LambdaIntegration(test_lambda)
)
response_200 = aws_apigateway.IntegrationResponse(
status_code="200"
)
method_200 =aws_apigateway.MethodResponse(
status_code="200"
)
credential_role = aws_iam.Role(
self,
"s3_role",
assumed_by=aws_iam.ServicePrincipal("apigateway.amazonaws.com"),
managed_policies=[aws_iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3FullAccess")]
)
s3_endpoint_integration = aws_apigateway.AwsIntegration(
service="s3",
integration_http_method="GET",
options=aws_apigateway.IntegrationOptions(
credentials_role=credential_role,
integration_responses=[response_200]
),
path=f"{s3_bucket.bucket_name}/${{stageVariables.stage_name}}/file.json",
)
s3_endpoint.add_method(
"GET",
s3_endpoint_integration,
method_responses=[method_200]
)
The code for the Lambda:
import json
def handler(event, context):
body = {"Error": "Not found"}
if event['stageVariables'].get('stage_name') == 'v1':
body = {"hi": "From V1"}
elif event['stageVariables'].get('stage_name') == 'v2':
body = {"hi": "From V2"}
return {
"statusCode": 200,
"body": json.dumps(body)
}
Given the API is called using the /v1/lambdas
endpoint it will return:
{"hi": "From V1"}
Given the API is called using the /v2/lambdas
endpoint it will return:
{"hi": "From V2"}
Given there is a file under the path v1/file.json
in the S3 bucket the file contents will be returned using the endpoint v1/test_s3
Given there is a file under the path v2/file.json
in the S3 bucket the file contents will be returned using the endpoint v2/test_s3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With