DEV Community

Navapon
Navapon

Posted on

Crafting a Custom SAM Template for Your AWS Lambda Function, Resource, and Operations

Nowadays, Serverless is widely adopted. The AWS Lambda Helps your organization focus on just the Code that needs to be done for business purposes.

Boost up development speed and do not need to handle infrastructure and operations.

On the first days of the development process, we might do it via console, write your code, and trigger; oh, that's working, and my job is done.

But as time passed, the System got more and more complex to many resources, and there are many stuff to be concerned about like code quality, Deployment Operation, Security, and Dependency of your code. There is a variety of tools that help you develop and deploy lambda to AWS, like serverless framework and terraform

Today, I would like to introduce and recommend AWS SAM to help you customize your organization lambda and resources standard embedded with CICD. These valuable tools help you standardize.

AWS SAM

AWS SAM is the native tools that help manage and handle serverless components and resources with predefined template powered by Cloudformation and cookiecutter that allow you to quickstart project with templates base on different use-case Before going to craft with custom template on your own I will show you how to get start working with aws predefined template first

Pre-requisites before getting start

brew install aws-sam-cli
sam init
Enter fullscreen mode Exit fullscreen mode

After using the init command, the prompt will respond by pressing 1. All templates will be displayed. You can select a suitable one by following the prompt instructions.

sam-init

Crafting Custom SAM Template

I would not like to explain how Sam works, just focusing on creating a custom template and working with sam-cli. Feel free to learn more about SAM here

Alright, let's get started.

Template Structure

The Template structure itself looks like the one below.

├── LICENSE
├── README.md
├── cookiecutter.json
├── template1
|  ├── cookiecutter.json
|  ├── hooks
|  |  ├── post_gen_project.py
|  |  └── pre_gen_project.py
|  └── {{cookiecutter.project_slug}}
|     ├── src
|     └── template-local.yaml
└── template2
   ├── cookiecutter.json
   ├── hooks
   |  ├── post_gen_project.py
   |  └── pre_gen_project.py
   └── {{cookiecutter.project_slug}}
      ├── src
      └── template-local.yaml

directory: 8 file: 11
Enter fullscreen mode Exit fullscreen mode

cookiecutter.json at the top level will prompt the user to choose a template with the following configuration.

{
  "template": [
    "Lambda Stand Alone (./template1)",
    "Lambda with Scheduler (./template2"
  ]
}
Enter fullscreen mode Exit fullscreen mode

The cookiecuuter.json at the second level will configure the prompt the user needs to follow and enter the appropriate value based on what you need to input.

Example

{
  "project_name": "Your Git Repository Name",
  "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('_','-') }}",
  "run_time": [
    "nodejs22.x",
    "python3.13",
    "java21",
    "go1.x"
  ],
  "project": [
    "project1",
    "project2",
    "project3"
  ],
  "project_description": "Tell more about Project Description",
  "ownership_team": [
    "teamA",
    "teamB",
    "teamC"
  ],
  "squad": [
    "squadA",
    "squadB",
    "squadC"
  ],
  "ownership_name": "",
  "github_user": "",
  "__prompts__": {
    "project_name": "Type your Github Repository Project Name.",
    "project_slug": "Auto converting name convention to be is that ok ?",
    "run_time": "Lambda Runtime Language.",
    "project": "This Lambda is part of which project.",
    "project_description": "What is the primary purpose of this service.",
    "ownership_team": "Select Projects Belong to which team.",
    "ownership_name": "Your Name Please.",
    "squad": "This project belongs to which Squad.",
    "github_user": "Your GitHub username see at github.com/yourprofilename"
  }
}
Enter fullscreen mode Exit fullscreen mode

The above variables can be accessed by using {{ cookiecutter.variables_name }} like {{ cookiecutter.project_slug }} for get dynamic inputs from user to the templates

Template example

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  Lambda {{ cookiecutter.project_slug }} Sandbox/SIT Environment stack belong to {{ cookiecutter.ownership_team }} Team own by {{ cookiecutter.ownership_name }}

Parameters:
  FunctionName:
    Type: String
    Default: "{{ cookiecutter.project_slug}}"
    Description: FunctionName inject params name conventions {repository-name}-{env} from workflows
  FunctionDescription:
    Type: String
    Default: >
      {{ cookiecutter.project_description }}
      This service created by team {{ cookiecutter.ownership_team }} [{{ cookiecutter.ownership_name }}]
    Description: Function Description Show at lambda
  Project:
    Type: String
    Default: "{{ cookiecutter.project }}"
  Team:
    Type: String
    Default: "{{ cookiecutter.ownership_team }}"
  Environment:
    Type: String
    Default: "sandbox"
  OwnershipName:
    Type: String
    Default: "{{ cookiecutter.ownership_name }}"
  DataClassification:
    Type: String
    Default: "confidential"
  Squad:
    Type: String
    Default: "{{ cookiecutter.squad }}"

Globals:
  Function:
    Timeout: 15
    Tracing: Active
  Api:
    TracingEnabled: true

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Ref FunctionName
      Description: !Ref FunctionDescription
      CodeUri: ./src
      Handler: app.lambdaHandler
      PackageType: Zip
      Runtime: "{{ cookiecutter.run_time }}"
      MemorySize: 256
      Timeout: 15
      Architectures:
        - "arm64"
      Role: arn:aws:iam::{{ cookiecutter.aws_account_id }}:role/lambda-role/{{ cookiecutter.project_slug }}-role
      # Also AWS Parameter and Secrets help you handle secrets value example here
      # https://aws.amazon.com/blogs/compute/using-the-aws-parameter-and-secrets-lambda-extension-to-cache-parameters-and-secrets/
      Layers:
        - !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:20"
        - !Sub "arn:aws:lambda:${AWS::Region}:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:12"
      Environment:
        Variables:
          ENV_NAME: "ENV_VALUE"
      Tags:
        Name: !Ref FunctionName
        Description: !Ref FunctionDescription
        Project: !Ref Project
        Team: !Ref Team
        Environment: !Ref Environment
        OwnershipName: !Ref OwnershipName
        DataClassification: !Ref DataClassification
        Squad: !Ref Squad
      # VpcConfig:
Enter fullscreen mode Exit fullscreen mode

The above is a SAM template to configure binding value with cookiecutter. You can add more resources like eventbridge-scheduler,api-gateway and more and customize the configuration that matches your purpose of the template

More than that, the cookiescutter template itself is supported by the hooks events. You can code with Python and manage whatever you need via hooks. Look more here

I have create the simple template feel free to look at it here

How to work with your crafted template

It is very easy to access the custom template by following the command.

sam init -l your-folder # Template location (git, mercurial, http(s), zip, path).
sam init -h # for look more option

# Example

sam init -l git@github.com:Navapon/custom-sam-template.git

Enter fullscreen mode Exit fullscreen mode

The results Is below.

sam-init

Conclusion

Just give you an idea of how to implement a template for serverless in your organization; you can create multiple cases and embed the practice of your organization to the template like pre-commit, cicd, lambda-layer-secret, lambda-layer-powertools and more

I hope this Blog will help you create your custom template to help the team focus on the code and get all the good practices that your organization followed the same standardization.

Top comments (0)