DEV Community

Sachin Lubana
Sachin Lubana

Posted on

Cloudformation: Lambda with HTTP API Gateway

Hey, Welcome!

In this post I am going to share how you can quickly setup a cloudformation stack with HTTP API Gateway proxying requests to serverless lambda function.

You can read in my previous post on setting up an HTTP API gateway with custom domain.

To make it simpler, I will break it down into multiple steps.

If you are just interested in the yaml template simply scroll down to the end.

Step 1: Create serverless lambda function

  DemoFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: "nodejs12.x"
      InlineCode: |
        exports.handler = function(event, context, callback) {
            console.log(event);
            const response = {
                statusCode: 200,
                body: JSON.stringify('Hello Node rule 1')
            };
            callback(null, response);
        };
Enter fullscreen mode Exit fullscreen mode

The above code creates serverless lambda function.

This lambda function basically uses

  • nodejs12.x as runtime
  • inline source code which can be CodeUri property that reference the source code from file

Step 2: Enable lambda invoke permission

  DemoLambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref DemoFunction
      Action: "lambda:InvokeFunction"
      Principal: apigateway.amazonaws.com
Enter fullscreen mode Exit fullscreen mode

The above code enables the lambda invoke from an api gateway You can read more about the lambda invoke permission.

Step 3: Create lambda proxy integration

  DemoIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref DemoHttpApi
      Description: Lambda proxy integration
      IntegrationType: AWS_PROXY
      IntegrationMethod: GET
      PayloadFormatVersion: "2.0"
      IntegrationUri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DemoFunction.Arn}/invocations'
Enter fullscreen mode Exit fullscreen mode

The above code integrates the lambda function with an HTTP api gateway.
You can read more about the lambda proxy integration here

Step 4: Create api route

  DemoApiRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref DemoHttpApi
      RouteKey: "GET /demo"
      AuthorizationType: AWS_IAM
      Target: !Join
        - /
        - - integrations
          - !Ref DemoIntegration
Enter fullscreen mode Exit fullscreen mode

The above code creates an api route with requests targeted to the lambda proxy integration.

I have configured authorization type as AWS_IAM which means the calling client (IAM role) must have permission to execute API gateway.

I use this API gateway for internal service communication where the calling site is another lambda function.

It implies that my lambda function X requests data from api gateway which proxies the requests to lambda function Y and this request is authenticated using AWS_IAM mechanism.

Step 5: Call site lambda function

  DemoCallFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs12.x
      CodeUri: dist/lambda/demoCall/
      Policies:
        - AmazonAPIGatewayInvokeFullAccess
Enter fullscreen mode Exit fullscreen mode

That is all you need to integrate lambda function with an HTTP api gateway.

You can use the below template to create cloudformation stack with all the above resources we talked about.

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Lambda with HTTP API gateway demo stack

Resources:
  ##########################################
  ##  create your API gateway resources   ##
  ##  as described in my previous post    ##
  ##########################################

  DemoFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: "nodejs12.x"
      InlineCode: |
        exports.handler = function(event, context, callback) {
            console.log(event);
            const response = {
                statusCode: 200,
                body: JSON.stringify('Hello Node rule 1')
            };
            callback(null, response);
        };

  DemoLambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref DemoFunction
      Action: "lambda:InvokeFunction"
      Principal: apigateway.amazonaws.com

  DemoIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref DemoHttpApi
      Description: Lambda proxy integration
      IntegrationType: AWS_PROXY
      IntegrationMethod: POST
      PayloadFormatVersion: "2.0"
      IntegrationUri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DemoFunction.Arn}/invocations'

  DemoApiRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref DemoHttpApi
      RouteKey: "GET /demo"
      AuthorizationType: AWS_IAM
      Target: !Join
        - /
        - - integrations
          - !Ref DemoIntegration

Enter fullscreen mode Exit fullscreen mode

In my next post, I will be sharing how we can connect a lambda function to an application load balancer.

Top comments (2)

Collapse
 
d6u profile image
Daiwei

Very useful! Thanks for writing this.

One minor change that can simplify the template by a few characters is instead of IntegrationUri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DemoFunction.Arn}/invocations', I tested we can also use IntegrationUri: !GetAtt DemoFunction.Arn, which still works.

Collapse
 
dinckan_berat profile image
BERAT DİNÇKAN

thank you so much ! this article is very helpful.