Deploying API Gateway and Lambda with CloudFormation

November 21, 2016 by Paulina BudzoƄ

Combination of AWS API Gateway and Lambda functions is a flag example of every “serverless infrastructure”. When deploying API Gateway with CloudFormation there are two different ways you can define your API: via Swagger template or by directly defining your methods in CloudFormation template.

For API Gateway you need at least 3 basic elements:

  • AWS::ApiGateway::RestApi
  • AWS::ApiGateway::Deployment
  • AWS::ApiGateway::Stage

If you want to find out more about what each of those are, check out APIGateway documentation.

To use a Swagger template, simply use the BodyS3Location parameter on the AWS::ApiGateway::RestApi. To automatically connect your API calls to the Lambda backend, you’ll need to include additional information inside your Swagger file - a x-amazon-apigateway-integration object, documented here: AWS documentation on x-amazon-apigateway-integration .

If you’re defining the methods and resources within CloudFormation template, you need to define the following objects: AWS::ApiGateway::Resource and AWS::ApiGateway::Method.

For an example simple integration, where API Gateway methods are defined within the CloudFormation template, see:
Using troposphere: apigateway_with_lambda.py
Final JSON template: apigateway_with_lambda.json

To make API Gateway work with a Lambda function, you need to define the Lambda with its role (as needed) and a permission (AWS::Lambda::Permission) for API Gateway to execute your Lambda.

Example of defining the permission:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from troposphere import awslambda

awslambda.Permission(
    "APILambdaPermission",
    Action="lambda:InvokeFunction",
    FunctionName=...,
    Principal="apigateway.amazonaws.com",
    SourceArn=Join("", [
        "arn:aws:execute-api:",
        Ref("AWS::Region"),
        ":",
        Ref("AWS::AccountId"),
        ":",
        Ref(api),
        "/*/GET/*"
    ])
)


The same as CloudFormation JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
"APILambdaPermission": {
    "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": ...,
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {
            "Fn::Join": [
                "",
                [
                    "arn:aws:execute-api:",
                    { "Ref": "AWS::Region" },
                    ":",
                    { "Ref": "AWS::AccountId" },
                    ":",
                    { "Ref": "API" },
                    "/*/GET/*"
                ]
            ]
        }
    },
    "Type": "AWS::Lambda::Permission"
}

Because neither Ref nor GetAtt functions can return an ARN for an API Gateway element, you have to build it yourself within the template. It follows this structure:

arn:aws:execute-api:REGION:ACCOUNT_ID:API_ID:API_STAGE:HTTP_METHOD:RESOURCE

In the example above, we allow the Lambda to pass any GET calls to any stage of the API to any resource within the API. You can obviously modify those as needed.

For a full working example of a working application, check out this stack using troposphere: Image Gateway API.

Posted in: CloudFormation