1. Introduction
In this article, we are going to learn about Lambda function creating, building, updating, and testing locally.
We can use AWS SAM to achieve this.
1.1 What is SAM
the AWS Serverless Application Model (SAM) is an open-source framework for building serverless applications. It provides shorthand syntax to express functions, APIs, databases, and event source mappings. With just a few lines per resource, you can define the application you want and model it using YAML.
During deployment, SAM transforms and expands the SAM syntax into AWS CloudFormation syntax, enabling you to build serverless applications faster.
2. Setup the environment
2.1 Install AWS SAM CLI
You need to follow the below steps to install the AWS SAM.
2.2 Install Docker Desktop
Follow, and install the docker application on your desktop.
2.3 Authenticate AWS using AWS CLI
Follow AWS CLI, to authenticate your AWS account.
3. Create a project
Step 01: Create a folder and go inside of that folder. Here I'm using "sam-projects".
Inside of the folder run the below command to make sure your SAM installation is successful.
sam -h
Step 02: To create a new project run the sam init
command.
I'm using AWS Quick start template.
PS C:\sam_projects\sam init
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Choose an AWS Quick Start application template
1 - Hello World Example
2 - Data processing
3 - Hello World Example with Powertools for AWS Lambda
4 - Multi-step workflow
5 - Scheduled task
6 - Standalone function
7 - Serverless API
8 - Infrastructure event management
9 - Lambda Response Streaming
10 - Serverless Connector Hello World Example
11 - Multi-step workflow with Connectors
12 - GraphQLApi Hello World Example
13 - Full Stack
14 - Lambda EFS example
15 - Hello World Example With Powertools for AWS Lambda
16 - DynamoDB Example
17 - Machine Learning
Template: 1
Use the most popular runtime and package type? (Python and zip) [y/N]: y
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: N
Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N
Would you like to set Structured Logging in JSON format on your Lambda functions? [y/N]: y
Structured Logging in JSON format might incur an additional cost. View https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-pricing for more details
Project name [sam-app]: sam-app2
Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)
-----------------------
Generating application:
-----------------------
Name: sam-app2
Runtime: python3.9
Architectures: x86_64
Dependency Manager: pip
Application Template: hello-world
Output Directory: .
Configuration file: sam-app2\samconfig.toml
Next steps can be found in the README file at sam-app2\README.md
Commands you can use next
=========================
[*] Create pipeline: cd sam-app2 && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app2 && sam validate
[*] Test Function in the Cloud: cd sam-app2 && sam sync --stack-name {stack-name} --watch
Now you see your project has been created.
Step 03: Explaining project structure
** I have deleted "tests" folder. We do not need that for this lesson.
Let's start with template.yaml
file.
SAM is that it deploys and maintains all of your resources, this is very similar to CloudFormation, actually this uses CloudFormation to deploy your resources and create a change set to update your resources.
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app2
Sample SAM Template for sam-app2
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
MemorySize: 128
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogFormat: JSON
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: Hello World Lambda Function ARN
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !GetAtt HelloWorldFunctionRole.Arn
So here, we do not need the below sections. I'm removing them to keep simple of the template.yaml file.
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: Hello World Lambda Function ARN
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !GetAtt HelloWorldFunctionRole.Arn
and,
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
and also,
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
MemorySize: 128
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogFormat: JSON
My python runtime environment is set to Python 3.12, hence I'm changing it.
Final template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app2
Sample SAM Template for sam-app2
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.12
Architectures:
- x86_64
The resource name is "HelloWorldFunction"
So we have our actual lambda function called "app.py"
app.py
import json
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world",
# "location": ip.text.replace("\n", "")
}),
}
Events: We can send test events to our function to test it locally.
Step 04: Now we want to rebuild this so, we are using sam build
. This creates like a build folder of our latest lambda function.
PS C:\sam_projects\sam-app2> sam build
Starting Build use cache
Manifest file is changed (new hash: 3298f13ca931dd4d421) or dependency folder (.aws-sam\deps\48421c5a-c936-9d9-443b05eeae8c) is missing for (HelloWorldFunction), downloading dependencies and
copying/building source
Building codeuri: C:\sam_projects\sam-app2\hello_world runtime: python3.12 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:CleanUp
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
Running PythonPipBuilder:CopySource
Build Succeeded
Built Artifacts : .aws-sam\build
Built Template : .aws-sam\build\template.yaml
Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
So now we can see .aws-sam
folder below,
In the build folder within that in our lambda function this hello world function and see it has all of the requests dependencies so we could just right-click open it and zip it up and upload it in lambda it's it's everything you need all of your dependencies in one folder.
Every time you make changes make sure to rebuild.
Step 05:
let's say this is the first iteration and we want to deploy these resources it's as simple as and you see it right here in the commands to deploy sam deploy guided guided kind of walks us through the first process of deploying it so let's type that in
sam deploy --guided
PS C:\sam_projects\sam-app2> sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app2]:
AWS Region [us-east-1]: us-west-2
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: Y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment:
Creating the required resources...
Successfully created!
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxx
A different default S3 bucket can be set in samconfig.toml and auto resolution of buckets turned off by setting resolve_s3=False
Parameter "stack_name=sam-app2" in [default.deploy.parameters] is defined as a global parameter [default.global.parameters].
This parameter will be only saved under [default.global.parameters] in C:\sam_projects\sam-app2\samconfig.toml.
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
Uploading to sam-app2/c43cafb817866506 532993 / 532993 (100.00%)
Deploying with following values
===============================
Stack name : sam-app2
Region : us-west-2
Confirm changeset : True
Disable rollback : True
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxx
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
Initiating deployment
=====================
Uploading to sam-app2/86dc15e504ed4983627c.template 516 / 516 (100.00%)
Waiting for changeset to be created..
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add HelloWorldFunctionRole AWS::IAM::Role N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:us-west-2:xxxxxxxx:changeSet/samcli-deploy17981/5866bc24-2
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:
Now if we go to cloud formation we should see two stacks if this is the first time you've deployed with SAM you'll see two stacks.
The first stack is the SAM CLI managed default and this is it creates an s3 bucket to store your artifacts so this is a one-time thing once you do this the first time you use sam then the subsequent deployments your artifacts will just be added to this.
The other stack named sam-app2 is your resource this is what we're deploying so it's a status of review in progress let's go back to our project and see that it's waiting for me to confirm it.
Waiting for changeset to be created..
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add HelloWorldFunctionRole AWS::IAM::Role N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:us-west-2:xxxxxxxx:changeSet/samcli-deploy11/5866b57-08875
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: Y
choose Y
and press enter. It should deploy the lambda function in the role.
Now you can see the below in your CMD.
Deploy this changeset? [y/N]: Y
2024-01-06 17:18:59 - Waiting for stack create/update to complete
CloudFormation events from stack operations (refresh every 5.0 seconds)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::CloudFormation::Stack sam-app2 User Initiated
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole -
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation Initiated
CREATE_COMPLETE AWS::IAM::Role HelloWorldFunctionRole -
CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction -
CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction Resource creation Initiated
CREATE_COMPLETE AWS::Lambda::Function HelloWorldFunction -
CREATE_COMPLETE AWS::CloudFormation::Stack sam-app2 -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-app2 in us-west-2
Now you can see in the CloudFormation that "sam-app2" is completed.
If we go to lambda functions we should see that function.
So we learned how to create one how to build it how to, deploy it Now we need to learn how to test it and how to update it.
Step 06: Test it and Update it.
So go back to your lambda function be sure you're not working in the build folder go back to your lambda function your app.py
and let's add some stuff to it.
app.py
import json
def lambda_handler(event, context):
first_name = event['first_name']
message = event['message']
return {
"statusCode": 200,
"body": json.dumps({
"message": f"{message} {first_name}",
# "location": ip.text.replace("\n", "")
}),
}
So how do we test this locally well there's a folder here called events with an event.json
file in it and this was created with our template it's got a ton of information. So we just delete that content and create a simple one.
event.json
{
"first_name": "Randika",
"message": "Hi"
}
Now we can test it locally.
Step 07: Npw we want to build it again.
Run the below command again.
sam build
You'll see it invoke the function with sam local invoke let's try that out.
sam local invoke HelloWorldFunction -e events/event.json
You see the below output,
PS C:\sam_projects\sam-app2> sam local invoke HelloWorldFunction -e events/event.json
Invoking app.lambda_handler (python3.12)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.12-rapid-x86_64.
Mounting C:\sam_projects\sam-app2\.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: 20e25543-e2c0-4ad7-9193-9a5547529f34 Version: $LATEST
END RequestId: acb97b8f-6f7d-4385-8759-740cbc67ca51
REPORT RequestId: acb97b8f-6f7d-4385-8759-740cbc67ca51 Init Duration: 0.03 ms Duration: 83.20 ms Billed Duration: 84 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"Hi Randika\"}"}
[ERROR] [1704549897802] LAMBDA_RUNTIME Failed to get next invocation. No Response from endpoint
Traceback (most recent call last):
File "/var/lang/lib/python3.12/site-packages/awslambdaric/lambda_runtime_client.py", line 86, in wait_next_invocation
PS C:\Users\UPERE51\Documents\Personal\Developments\sam_projects\sam-app2>
You can see the below message in the above output.
{"statusCode": 200, "body": "{\"message\": \"Hi Randika\"}"}
That's how we test it.
Step 08:
We want to update the lambda function in AWS, we don't need to do Ssam deploy guided again, because we have this sam config tomo file that says hey here's the stack name here's the s3 bucket here's the region.
We're just going to do sam deploy
.
sam deploy
Output:
PS C:\sam_projects\sam-app2> sam deploy
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxx
A different default S3 bucket can be set in samconfig.toml
Or by specifying --s3-bucket explicitly.
Uploading to sam-app2/61f5bc 533019 / 533019 (100.00%)
Deploying with following values
===============================
Stack name : sam-app2
Region : us-west-2
Confirm changeset : True
Disable rollback : True
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxx
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
Initiating deployment
=====================
Uploading to sam-app2/62.template 516 / 516 (100.00%)
Waiting for changeset to be created..
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Modify HelloWorldFunction AWS::Lambda::Function False
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
2024-01-06 19:40:53 - Waiting for stack create/update to complete
CloudFormation events from stack operations (refresh every 5.0 seconds)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS AWS::CloudFormation::Stack sam-app2 User Initiated
UPDATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction -
UPDATE_COMPLETE AWS::Lambda::Function HelloWorldFunction -
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS AWS::CloudFormation::Stack sam-app2 -
UPDATE_COMPLETE AWS::CloudFormation::Stack sam-app2 -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-app2 in us-west-2
We should see in cloud formation the change set created. Let's go to the "sam-app2" and go to change sets and you can see the below
And that's it that's your workflow for developing lambda functions locally.
Top comments (2)
AweSome !! Keep It Bro
Thank you @lasanthasilva :)