Serverless apps using Lambda and API Gateway – HTTP API

Serverless app using Lambda & API Gateway with CloudFormation.

Creating Serverless Application with API Gateway and Lambda

We will combine two resources to create a simple serverless web application.

The first is Lambda. Lambda is a FaaS service provided by AWS.

AWS Lambda is a serverless compute service that runs your code in response to events and automatically manages the underlying compute resources for you.

AWS Lambda Features

In this case, we will use Lambda as a computing resource for our web app.

The second is API Gateway, which is a fully managed service provided by AWS for building APIs.

Amazon API Gateway is a fully managed service that makes it easy for developers to publish, maintain, monitor, secure, and operate APIs at any scale.

Amazon API Gateway Features

Serverless applications with Lambda and API Gateway have several advantages over applications with servers. Compare, for example, installing Nginx or Apache on an EC2 instance and operating it as a web server.

First, let’s compare operational aspects: if you are running a web server, you will need to update the OS and middleware on a regular basis. In addition, logs are stored in the server, so you will need to consider periodically accessing and checking logs or distributing them to CloudWatch Logs. If the server is to be operated in a stable manner, it is also necessary to monitor the server by distributing metrics such as CPU usage to CloudWatch. Serverless applications, on the other hand, do not require this kind of effort, allowing you to focus only on the code executed by the Lambda functions.

Next, let’s compare the pricing aspects: If you build a web server to operate the system, you need to keep the server running at all times, and during that time, you will incur constant charges. In contrast, a serverless application consisting of API Gateway and Lambda is a pay-as-you-go system based on the number of accesses and time spent. Therefore, cost savings can be expected in many cases.

Finally, compare system elasticity: if you build a web server with EC2 instances, you would need to change the configuration to launch multiple instances with Auto Scaling to handle high traffic and distribute processing using ELB. In contrast, with a serverless application, the Lambda function automatically scales out, providing a high degree of elasticity.

Thus, serverless applications using API Gateway and Lambda have many advantages. This page introduces the simplest form of serverless applications. By deepening your understanding of serverless application configuration, you will have the opportunity to take advantage of the many benefits of serverless applications.

In this case, an HTTP type API Gateway is used.

For details on how to create a REST API type API Gateway, please refer to the following page.

あわせて読みたい
Create REST API type API Gateway using CFN 【Create REST API type API Gateway using CloudFormation】 The following page covers the HTTP API type API Gateway. https://awstut.com/en/2021/12/11/serverles...

Environment

Diagram of serverless app using Lambda & API Gateway.

Create an API Gateway and place Lambda in the backend.

In this simple configuration, when an HTTP request is received from a user, the API Gateway becomes the endpoint, calls a Lambda function instead, and returns the execution result of the function to the user.

The API Gateway is created using the HTTP API type.

The runtime environment for the Lambda function is Python 3.8.

CloudFormation template files

We will build the above configuration using CloudFormation.

Place the CloudFormation template at the following URL.

https://github.com/awstut-an-r/awstut-fa/tree/main/005

Template file points

We will cover the key points of each template file to configure this environment.

Grant the Lambda function the permission to execute the function

First, let’s check the definition of the function itself.

<meta charset="utf-8">Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - !Ref Architecture
      Code:
        ZipFile: |
          import json

          def lambda_handler(event, context):
            return {
              'statusCode': 200,
              'body': json.dumps('Hello form Awstut !')
            }
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

The Architectures property is a parameter to specify the underlying processor on which the Lambda function will be executed; as of September 29, 2021, the function can be executed on the Arm-based Graviton2.

It is now possible to configure new and existing functions to run on x86 or Arm/Graviton2 processors.

This choice saves you money in two ways. First, the Graviton2 architecture allows functions to be executed more efficiently. Second, you pay less for the time it takes to execute. In fact, Lambda functions powered by Graviton2 are designed to deliver up to 19% better performance at 20% lower cost.

AWS Graviton2 プロセッサを搭載した AWS Lambda 関数 – Arm で関数を実行し、最大 34% 優れた料金パフォーマンスを実現

This property is set to “x86_64” by default, but in this case, by referring to the variable with the built-in function Fn::Ref and specifying “arm64”, the function can be executed on Graviton2.

In the Code property, configure the settings regarding the code to be executed by the Lambda function. As shown below, you can prepare the code to be executed by the function in three different ways.

To deploy a function defined as a container image, you specify the location of a container image in the Amazon ECR registry. For a .zip file deployment package, you can specify the location of an object in Amazon S3. For Node.js and Python functions, you can specify the function code inline in the template.

AWS::Lambda::Function Code

This time, the code will be written inline in the template file.

For information on how to inline the code to be executed by the Lambda function, please see below.

あわせて読みたい
3 parterns to create Lambda with CloudFormation (S3/Inline/Container) 【Creating Lambda with CloudFormation】 When creating a Lambda with CloudFormation, there are three main patterns as follows. Uploading the code to an S3 buc...

Check the code to be executed.

The content is a dictionary type, which simply returns a string in JSON format along with a status code in Python.

The Handler property is a parameter that defines the function to be executed when the function is called. As mentioned above, we have defined the lambda_handler function, so specify the name of the function.

The Runtime property is a parameter that specifies the runtime environment for the function. In this case, we will specify Python 3.8 to run the function.

In the Role property, we need to specify the IAM role associated with the function. In this case, we will define the IAM role as shown below, and specify that it refers to this role.

Resources:
  FunctionRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Code language: YAML (yaml)

In the ManagedPolicyArns property, associate the AWS management policy with the IAM role to be created. In this case, we will specify AWSLambdaBasicExecutionRole. The contents of this policy are as follows.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
Code language: JSON / JSON with Comments (json)

This is to provide permissions for writing to CloudWatch Logs.

To create an API Gateway, five resources need to be defined

When building an environment to execute Lambda through API Gateway, prepare the following five resources.

  1. API Gateway
  2. Stage
  3. Integration
  4. Route
  5. Authority for API Gateway to call Lambda functions

Check them in order.

API Gateway

First, check the API Gateway itself.

Resources:
  HttpApi:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: !Sub "${Prefix}-HttpApi"
      Description: HttpApi.
      ProtocolType: HTTP
Code language: YAML (yaml)

Specify the type of API Gateway to be created in the ProtocolType property.

When creating a RESTful API with API Gateway, you can choose between two types: HTTP API and REST API.

With API Gateway, you can create RESTful APIs using either HTTP APIs or REST APIs. HTTP APIs are the best way to build APIs that do not require API management features. HTTP APIs are optimized for serverless workloads and HTTP backends—they offer up to 71% cost savings and 60% latency reduction compared to REST APIs from API Gateway.

Amazon API Gateway Features

In this case, we will specify “HTTP” for this property and make it an HTTP API type.

Stage

Next, check the Stage.

Resources:
  Stage:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      ApiId: !Ref HttpApi
      AutoDeploy: true
      StageName: $default
Code language: YAML (yaml)

You can prepare stages and build a staging environment for development or production.

An API stage is a logical reference to a lifecycle state of your API (for example, devprodbeta, or v2). API stages are identified by their API ID and stage name, and they’re included in the URL you use to invoke the API.

Working with stages for HTTP APIs

This time, you can create a default endpoint by specifying “$default” for the StageName property.

You can create a $default stage that is served from the base of your API’s URL—for example, https://{api_id}.execute-api.{region}.amazonaws.com/.

Working with stages for HTTP APIs

Integration

Then check the integration.

Resources:
  Integration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref HttpApi
      ConnectionType: INTERNET
      CredentialsArn: !GetAtt ApiGatewayRole.Arn
      IntegrationMethod: POST
      IntegrationType: AWS_PROXY
      IntegrationUri: !Ref FunctionArn
      PayloadFormatVersion: "2.0"
Code language: YAML (yaml)

Integration is the middleman between API Gateway itself and resources such as Lambda.

Integrations connect a route to backend resources. HTTP APIs support Lambda proxy, AWS service, and HTTP proxy integrations.

Configuring integrations for HTTP APIs

In this configuration, the API Gateway sends a request from the API Gateway to the Lambda function, which is a backend resource, via the integration, and the response from the Lambda function is returned to the API Gateway.

Specify the API Gateway body in the ApiId property. Specify the aforementioned body resource by referencing it with the Ref function.

The ConnectionType property specifies the connection type to the integration endpoint. This property can be set to “INTERNET” or “VPC_LINK,” but in this case, we will use Lambda outside the VPC as the backend resource, so specify “INTERNET.

The CredentialsArn property is a property related to the permissions required for API Gateway to call the backend resource. Specify the ARN of the IAM role described below.

The IntegrationType property is a parameter that specifies the integration type. If you are using a Lambda function as a backend resource, select Lambda proxy integration.

A Lambda proxy integration enables you to integrate an API route with a Lambda function. When a client calls your API, API Gateway sends the request to the Lambda function and returns the function’s response to the client.

Working with AWS Lambda proxy integrations for HTTP APIs

When using the Lambda proxy integration, specify “AWS_PROXY” for the IntegrationType property.

In the case of Lambda proxy integration, the value to be specified for the IntegrationMethod property is fixed.

For Lambda integrations, you must use the HTTP method of POST for the integration request, according to the specification of the Lambda service action for function invocations.

Set up Lambda proxy integration using the AWS CLI

As described above, specify “POST” for this property.

Specify the backend resource to be called in the IntegrationUri property. In this case, we will be calling a Lambda function, so we will specify the Lambda function described above.

The PayloadFormatVersion property is a parameter that specifies the version of the payload used to mediate between API Gateway and the backend resource. In this case, we will specify the latest version, “2.0”.

Route

Check the route definition.

Resources:
  Route:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref HttpApi
      RouteKey: "GET /"
      Target: !Sub "integrations/${Integration}"
Code language: YAML (yaml)

Route is a resource for tying HTTP methods and URLs to backend resources.

Routes direct incoming API requests to backend resources. Routes consist of two parts: an HTTP method and a resource path—for example, GET /pets. You can define specific HTTP methods for your route.

Working with routes for HTTP APIs

Specify the HTTP method and URL to be associated with the RouteKey property. In this case, we will specify “‘GET /'” to define the route for the endpoint when it is requested to the root URL by GET.

Specify the routing destination in the Target property. The routing destination can be a predefined integration. In this case, we will use the built-in function Fn::Sub and specify it by embedding the ID of the integration resource described earlier.

Authority for API Gateway to call Lambda functions

The CredentialsArn property of the integration resource mentioned above, specify the following IAM roles.

Resources:
  ApiGatewayRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - apigateway.amazonaws.com
      Policies:
        - PolicyName: !Sub "${Prefix}-InvokeFunctionPolicy"
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - lambda:InvokeFunction
                Resource:
                  - !Ref FunctionArn
Code language: YAML (yaml)

You can authorize the API Gateway to call backend resources in two ways, as follows

The IAM role of apigAwsProxyRole must have policies allowing the apigateway service to invoke Lambda functions… Instead of supplying an IAM role for credentials, you can call the add-permission command to add resource-based permissions.

Set up Lambda proxy integration using the AWS CLI

In this case, we will grant permissions to API Gateway by assigning the former IAM role.

Looking at the content of the policy, we can see that it grants permission to invoke the function by specifying “lambda:InvokeFunction” as Action and the Lambda function mentioned earlier as Resource.

As shown below, you can also use Lambda’s resource-based policy to grant API Gateway the permission to call the function.

Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref FunctionName
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
Code language: YAML (yaml)

Architecting

Using CloudFormation, we will build this environment and check its actual behavior.

Create CloudFormation stack and check resources in stacks

Create a CloudFormation stack.

For more information on how to create stacks and check each stack, please refer to the following page.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

From the AWS Management Console, you can also check the creation status of API Gateway related resources.

First, check the API Gateway itself and its stages.

HTTP API and Default stage.

You can see that the API Gateway itself has been successfully created. You can also see that the stage name “$default” stage has been created. You can now use the API Gateway root URL without including the stage name.

Next, let’s check the integration.

Lambda and IAM roles are associated with Integration.

Through the integration, we can see that the Lambda function we created is associated with API Gateway. We can also see that the IAM role with the permissions to call the function is also associated with it.

Finally, let’s check the route.

Integration is assigned to the API Gateway root URL.

You can see that the API Gateway root URL is associated with the aforementioned integration. Now, when the API Gateway root URL is accessed, the Lambda function associated with the integration will be called.

Checking Operation: Accessing API Gateway Endpoint

Now that we are ready, let’s access the API Gateway.

The API endpoint created in the API Gateway is a combination of the API ID and region information, as shown below.

API endpoint
A hostname for an API in API Gateway that is deployed to a specific Region. The hostname is of the form {api-id}.execute-api.{region}.amazonaws.com.

Amazon API Gateway concepts

Following the above, the API endpoint created this time will be “https://io3gltn5gi.execute-api.ap-northeast-1.amazonaws.com”.

Let’s actually access it.

$ curl https://<meta charset="utf-8">io3gltn5gi.execute-api.ap-northeast-1.amazonaws.com/
"Hello form Awstut !"
Code language: Bash (bash)

The string was returned successfully.

By the way, if you access an undefined route, you will get an error message.

$ curl https://<meta charset="utf-8">io3gltn5gi.execute-api.ap-northeast-1.amazonaws.com/hogehoge
{"message":"Not Found"}
Code language: Bash (bash)

As described above, when a user accesses an API endpoint, if the request is for a URL or HTTP method defined in the route, a Lambda function will be executed via the integration. Then, the HTTP response is returned to the user through the integration and API Gateway again.

Summary

We have seen how to build simple serverless applications with Lambda functions and API Gateways, and we have seen that when creating an API Gateway, we need to combine five resources including the main body. A better understanding of serverless application configuration will give you the opportunity to take advantage of the many benefits of serverless applications.