AWS: Lambda functions – an overview, and integration with AWS API Gateway

By | 08/18/2021
 

AWS Lambda allows running a code without the need to create and manage servers, also known as the serverless approach.

AWS Lambda will determine how much CPU and memory is needed to run a function, and when it’s necessary it will perform autoscaling.

A code to be running is organized in lambda functions and can be triggered with triggers. Results can be checked using CloudWatch Logs.

As a trigger, you can use almost any AWS service such as API Gateway, SQS, Application LoadBalancer, CloudFront, Kinesis, or an external event, for example, a webhook from Github.

In this post, we will create a simple AWS Lambda function, will check its control panel, available options, and features, and then will create an AWS API Gateway which will forward HTTP requests to an AWS Lambda function.

AWS Lambda – use cases

In general, Lambda in AWS can do really a lot of things. Such a “silver bullet”, allowing to do things that are not realized by the AWS Console itself.

Example use cases could be:

  • a website: a javascript-based frontend in AWS S3 with Static hosting, frontend will receive requests via an AWS API Gateway to a database via a Lambda function
  • log analyzes: a good example is AWS WAF Security Automations, when all incoming HTTP requests are sent to the AWS Kinesis, it will forward them to the Lambda, it will perform some checks, and if needed will block a client’s IP
  • backups automation: AWS SNS can send an event, for example when too much disk space is used in an AWS S3 bucket, to a Lambda function, that will delete some old backups
  • data processing: for example, when a new file is uploaded to an AWS S3, it will generate an event that will trigger a Lambda function that will perform a video file encoding
  • serverless cronjobs: with CloudWatch Events generate an event by a schedule, that will trigger a Lambda function

Components and concepts

Let’s take a short overview of the AWS Lambda main concepts:

Creating a “Hello, World” Lambda function

At first, let’s create the simplest Lambda function to see how it’s working and what do we have there.

Create a function

Go to the AWS Lambda, click on the Create function:

For now, let’s use an existing template. Choose the Use a blueprint, find a hello-world-python:

Click on the Configure:

Set a function’s name, for example, example-hello, leave a default IAM role – it will allow our function to use CloudWatch Logs, and check the code that will be used:

Click on the Create function:

Switch to the Test tab:

Here, we can pass a JSON with data to be processed by our function.

Run it:

Now, let’s go to see what AWS Console suggests to use for Lambda function management.

Monitoring

The first thing is monitoring. Here we can use AWS CloudWatch metrics and logs, calls tracing with AWS X-Ray, Lambda insights, and AWS CodeGuru:

Configuration

General configuration

  • memory settings: a maximum RAM allowed to be used when running a function. Also, depending on the memory settings, Lambda will provide a CPU limit: for every 1769 MB, a one vCPU will be. See Configuring function memory (console).
  • execution timeouts: maximum can be set to 900 seconds, after that, a function execution will be stopped. Remember, that this will affect costs. See Timeout.
  • IAM role: includes IAM policies with permissions to AWS resources

Triggers

Well, triggers that will trigger our function.

Can be almost any AWS service:

For example, we can create a trigger from an AWS Application LoadBalancer that will accept connections  to a specific URI and will forward it to a Lambda function:

Permissions

Here, you can view and adjust IAM role and policies that will configure a function’s permissions:

Destinations

Where to send a function’s execution results.

For example, can be an AWS SNS topic that will forward it to Opsgenie that will send a message to a Slack channel:

Environment variables

Variables that can be used in our function. Sensitive data can be encrypted with AWS Key Management Service (KMS):

VPC

A function can be placed to a dedicated AWS Virtual Private Cloud to limit its network access:

Monitoring and operations tools

Monitoring settings, where you can enable or disable additional services such as AWS X-Ray, CloudWatch Lambda Insights, and Amazon CodeGuru Profiler:

In the Extentions, you can choose from a list of already existing solutions or create your own:

Concurrency

A maximum number of a function’s instances that can be run simultaneously. See Managing concurrency for a Lambda function.

Can be one of the two types:

  • reserved concurrency: reserve a number from the generally available for the whole account (1000 by default) and is applied to the whole function including all its versions and aliases
  • provisioned concurrency: will prepare an already initialized runtime environments so during scaling your function will not have to wait for it, applies to a specific version or an alias

Asynchronous invocation

Settings for the event queue – lifetime, number of retries in case of errors, errors notifications, etc.

See Asynchronous invocation:

See also Synchronous invocation and Asynchronous invocation.

Database proxies

An Amazon RDS Proxy configuration to be used with your function. RDS Proxy used to decrease a number of connections to a database server:

File system

You can mount an AWS Elastic File System directory inside your function:

Aliases

An alias is a kind of pointer to a specific version of your function’s code that can be used in its ARN later.

Also, you can have a couple of aliases and distribute requests between them. See Lambda function aliases:

Versions

AWS Lambda allows using a code and part of settings versioning. Can be useful when testing a new code on a Dev environment, for example by creating a dedicated alias:

AWS Lambda, and AWS API Gateway – an integration example

So, we’ve checked what AWS Lambda is and what it has in its settings.

Now, let’s create an AWS API Gateway that will forward requests to an AWS Lambda function.

API Gateway will accept requests to the /test URI and will use its event to send them to our Lambda.

Create a Lambda function

At this time, choose Author from scratch, in the Runtime use Python:

Leave the default code:

Here, the lambda_handler() is a default function to be called when a function is called. it accepts two arguments:

  1. event: an API Gateway event, see Using AWS Lambda with other services
  2. context: allowed methods and parameters to run a function, see AWS Lambda context object in Python

Create an AWS API Gateway

Create a new gateway, set its type to the HTTP API:

Add an integration:

Choose Lambda, an AWS Region, and a function to be called:

Set the URI as /test:

Leave the default stage:

In less than a minute your Gateway is ready. Copy its URL:

And try with thecurl:

curl https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test
"Hello from Lambda!"

To check the full content of the event, print it with the  json.dumps():

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps(event)
    }

After making a code changes, press on the Deploy:

Try it:

curl https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test
{"version": "2.0", "routeKey": "ANY /test", "rawPath": "/test", "rawQueryString": "", "headers": {"accept": "*/*", "content-length": "0", "host": "fwu399qo70.execute-api.us-east-2.amazonaws.com", "user-agent": "curl/7.78.0", "x-amzn-trace-id": "Root=1-611bbaa4-3cb7c28e4e3181dd647f1030", "x-forwarded-for": "194.***.***.29", "x-forwarded-port": "443", "x-forwarded-proto": "https"}, "requestContext": {"accountId": "534***385", "apiId": "fwu399qo70", "domainName": "fwu399qo70.execute-api.us-east-2.amazonaws.com", "domainPrefix": "fwu399qo70", "http": {"method": "GET", "path": "/test", "protocol": "HTTP/1.1", "sourceIp": "194.***.***.29", "userAgent": "curl/7.78.0"}, "requestId": "ENoZriIrCYcEPWg=", "routeKey": "ANY /test", "stage": "$default", "time": "17/Aug/2021:13:33:24 +0000", "timeEpoch": 1629207204179}, "isBase64Encoded": false}

Now, let’s see how we can use environment variables in the function.

Add a new one:

And print its value with the os.getenv():

import os
import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': os.getenv('Env')
    }

Check it:

curl https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test
test

Also, you can change the default handler.

Rename the lambda_handler to the main_handler:

import os
import json

def main_handler(event, context):
    return {
        'statusCode': 200,
        'body': os.getenv('Env')
    }

If you’ll try to access the function now, you’ll get the Internal Server Error:

curl https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test
{"message":"Internal Server Error"}

Scroll down to the Runtime settings:

And change the Handler:

Run it again:

curl https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test
test

Done.



Also published on Medium.