DEV Community

Cover image for Building a CRM with AWS SAM, part 1: ping
Claudio Guerra
Claudio Guerra

Posted on • Edited on

Building a CRM with AWS SAM, part 1: ping

Welcome to the first post in a series where I’ll walk through building a CRM (Customer Relationship Management) system using AWS SAM. We’ll progressively create a serverless backend, focusing on clean architecture, scalability, and cost optimization.

In this post, we'll set up our project and create a /ping health check endpoint to make sure everything is working.

Why Serverless and SAM?

One of the biggest benefits of serverless is that you don't need to worry about infrastructure maintenance, instead you assemble your system with serverless primitives that can scale based on demand, and therefore, you pay only for the resources you use.

AWS SAM (Serverless Application Model) simplifies serverless app deployment. SAM consists of the SAM CLI that helps test, build and deploy, and also SAM templates, which offers abstractions on top of the AWS Cloudformation syntax.

Project Setup

Let’s start by creating the simplest piece of functionality: a ping endpoint that returns "pong". This will serve as our health check route and confirm everything is wired correctly.

Folder structure:

├─ src/
│  └─ functions/
│    └─ ping/             # Ping function code
│      ├─ __init__.py
│      └─ app             # Ping function module
│        ├─ __init__.py
│        └─ main.py       # Lambda handler
├─ samconfig.toml         # SAM configuration
└─ template.yml           # SAM template
Enter fullscreen mode Exit fullscreen mode

We'll start with the most important piece of the puzzle, the SAM template, where we define all the infrastructure components our application will have, all defined as code (IaC), that means that we can version and track infrastructure changes in our git repository.

# template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: CRM SAM

Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod

  PingFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/functions/ping/
      Handler: app.main.lambda_handler
      Runtime: python3.13
      Events:
        Ping:
          Type: Api
          Properties:
            RestApiId: !Ref ApiGateway
            Path: /ping
            Method: GET

Outputs:
  PingUrl:
    Description: URL to ping endpoint
    Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/ping"
Enter fullscreen mode Exit fullscreen mode

In this template we can see we're defining the Resources we're gonna be using, which in this case are:

  • ApiGateway: an AWS::Serverless::Api that receives requests to be resolved by a lambda function, and then takes its response and hands it back to the caller.
  • PingFunction: an AWS::Serverless::Function that will be resolving the ping request and will create the response to be then returned by the API Gateway.

Here we can already notice a common theme, all resources are comprised by a Type which let's us define what kind of resource we're talking about, and Properties which corresponds to the configuration we'll be giving to that particular resource.

At the bottom we can also notice the Outputs section in which we can get different values from the resources that get generated at deployment time, which can be for reference or which can also be passed to other stacks in case we're building something more complex that involves multiple templates, in this case we're outputing the url we can hit to reach the ping function.

Now here's the code of the Lambda function:

# src/functions/ping/app/main.py
def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": '{"response": "pong"}'
    }
Enter fullscreen mode Exit fullscreen mode

Very minimal, just returns a status code 200 and "pong" in the body.

Finally, we have the samconfig.toml file where we configure parameters for different sam commands.

version = 0.1

[default]
[default.global.parameters]
stack_name = "crm-sam"
region = "us-east-1"

[default.build.parameters]
cached = true
parallel = true

[default.validate.parameters]
lint = true

[default.local_start_api.parameters]
warm_containers = "EAGER"
tags = "application=crm-sam"

[default.local_invoke.parameters]
tags = "application=crm-sam"

[default.logs.parameters]
tail = true

[default.deploy.parameters]
capabilities = ["CAPABILITY_IAM"]
confirm_changeset = false
resolve_s3 = true
s3_prefix = "crm-sam"
image_repositories = []
Enter fullscreen mode Exit fullscreen mode

Running it locally.

Before running anything you always need to build the application:

sam build
Enter fullscreen mode Exit fullscreen mode

Then you can run the project locally by using:

sam local start-api
Enter fullscreen mode Exit fullscreen mode

and then if you curl the endpoint with:

curl http://localhost:3000/ping
Enter fullscreen mode Exit fullscreen mode

you should get the following response

{"response": "pong"}
Enter fullscreen mode Exit fullscreen mode

Finally, you can deploy it to AWS by just running

sam deploy
Enter fullscreen mode Exit fullscreen mode

at the end of the deployment output you should see something like:

CloudFormation outputs from deployed stack
-------------------------------------------------------------------
Outputs                                                                                         
-------------------------------------------------------------------
Key                 PingUrl                                                                     
Description         URL to ping endpoint                                                        
Value               https://uywf3xcoej.execute-api.us-east-1.amazonaws.com/prod/ping            
-------------------------------------------------------------------
Enter fullscreen mode Exit fullscreen mode

which you can also curl

curl https://uywf3xcoej.execute-api.us-east-1.amazonaws.com/prod/ping
{"response": "pong"}
Enter fullscreen mode Exit fullscreen mode

What did we learn?

  • How to scaffold a minimal SAM project
  • How to define a Lambda function
  • How to expose a route using API Gateway
  • How to test it locally and deploy it

This simple GET /ping endpoint is the starting point of our CRM, from here, we'll expand into real CRM functionality.

I'll keep the code for this series in this repo, and the code for this post can be found here.

Coming Next

In the next post, we will create the first feature of our CRM: a POST /contacts endpoint to store contact information in AWS DynamoDB.

Top comments (2)

Collapse
 
cashoefman profile image
Cas Hoefman

When can we expect your next post? Do you have a github repo to go with it?

Collapse
 
claudio_codes profile image
Claudio Guerra • Edited

Hey there, I'll be keeping the code in this repo and I'll have the progress of each post in different branches. I will publish the next post in a few days.

Thanks for asking!