Build a serveless Backend

Building a Scalable Serverless CRUD Backend with AWS Lambda and Aurora MySQL
In the world of modern cloud architecture, Serverless is the gold standard for agility and cost-efficiency. But what does it actually mean?
Simply put, Serverless is a cloud computing model where the provider (AWS, in our case) manages the underlying servers. As developers, we focus solely on writing code. No provisioning, no patching, and no infrastructure maintenance.
Today, we’re building a To-Do app backend where both the compute (AWS Lambda) and the database (Amazon Aurora) run on serverless frameworks. This setup allows us to scale to zero when not in use, drastically reducing operational overhead and costs.
Part 1: Setting Up the Aurora Serverless V2 Database
To get started, head over to your AWS Console, search for RDS, and open the dashboard. Click on Create database.
Database Configuration
For this demo, we’ll choose the most cost-effective settings:
-
Creation Method: Choose Standard create (to access full configuration).
-
Engine Options: Select Amazon Aurora.
-
Edition: Select MySQL-Compatible Edition. (Note: PostgreSQL is an option, but SQL syntax differs slightly).
-
Templates: Pick Dev/Test. This automatically toggles several settings to minimize costs.
-
Settings:
-
DB cluster identifier: Name it
demo. -
Master username: Leave as
admin. -
Credentials management: Select Self managed.
-
Master password: Set something simple like
admin123.
-
-
Instance Configuration: Ensure Serverless v2 is selected.
-
Capacity Range: Set the Minimum ACU to 0.5 (or 1) and Maximum to 1 or 2 to keep it within a tight budget.
-
Availability & Durability: Choose Don't create an Aurora replica.
What is a Replica? In production, a replica is a "shadow" copy of your database in a different location. If your main database fails, the replica takes over instantly. For a demo, we skip this to save money.
Enabling the RDS Data API (Crucial Step!)
Scroll down to Connectivity and ensure the RDS Data API is checked.
Why is the Data API important? Traditionally, connecting Lambda to a database requires putting the Lambda inside a VPC, which complicates networking and adds "cold start" latency. The Data API allows Lambda to talk to the DB via a secure HTTPS endpoint. It is currently a feature of Aurora Serverless and certain Aurora clusters, rather than standard RDS instances.
Finalizing
Under Additional configuration, type demo as the Initial database name. Click Create database.
How to monitor creation: On the RDS dashboard, the status will show "Creating." Grab a coffee; once it turns "Available," you are ready to roll.
Part 2: Preparing the Schema
On the left sidebar, click Query Editor.
The Query Editor uses the Data API we just enabled. It allows you to run SQL commands directly from your browser without needing an external tool like MySQL Workbench.
Connect using the credentials we set (admin / admin123) and the database name demo. You'll see a default query; this is just a health check to ensure the engine is responsive.
Run the following SQL to create your table:
-- Create a schema for our app
CREATE DATABASE todo_app;
-- Create the table with UUIDs for IDs
CREATE TABLE todo_app.todos (
id CHAR(36) PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Seed some initial data
INSERT INTO todo_app.todos (id, title, completed)
VALUES
(UUID(), 'Set up Aurora MySQL cluster', FALSE),
(UUID(), 'Create todos table', TRUE),
(UUID(), 'Test Lambda CRUD functions', FALSE);
SQL Explained:
-
CREATE TABLE: Tells the DB to make a new container for data. -
CHAR(36): A fixed-length string to hold our unique ID. -
BOOLEAN: A true/false flag for completion. -
TIMESTAMP: Automatically records when the item was created.
Part 3: Building the Lambda Functions
To build a full CRUD app, we need five Lambda functions. When creating a function in the Lambda Console:
-
Click Create function.
-
Select Author from scratch.
-
Use Python 3.12 (or higher).
-
Under Execution role, we will create a custom role (see below).
The CRUD Code
Copy the code below for each respective function.
Important: Before pasting, you need two ARNs (Amazon Resource Names).
DB Cluster ARN: Found in the RDS Console under your cluster's "Configuration" tab.
Secret ARN: Found in the AWS Secrets Manager console (RDS automatically creates a secret for you if you chose managed credentials, or you can create one manually to store your admin/admin123 login).
1. List All Todos (GET)
import json
import boto3
rds_client = boto3.client('rds-data')
DATABASE_NAME = 'demo'
DB_CLUSTER_ARN = 'YOUR_CLUSTER_ARN'
DB_SECRET_ARN = 'YOUR_SECRET_ARN'
def lambda_handler(event, context):
sql = "SELECT id, title, completed, created_at FROM todo_app.todos ORDER BY created_at DESC"
response = rds_client.execute_statement(
resourceArn=DB_CLUSTER_ARN, secretArn=DB_SECRET_ARN, database=DATABASE_NAME, sql=sql
)
todos = []
for record in response.get('records', []):
todos.append({
"id": record[0]['stringValue'],
"title": record[1]['stringValue'],
"completed": record[2]['booleanValue'],
"created_at": record[3]['stringValue']
})
return {"statusCode": 200, "body": json.dumps(todos)}
2. Create Todo (POST)
import json, boto3, uuid
from datetime import datetime
rds_client = boto3.client('rds-data')
def lambda_handler(event, context):
body = event if 'title' in event else json.loads(event.get('body', '{}'))
todo_id = str(uuid.uuid4())
title = body.get('title', 'New Task')
sql = f"INSERT INTO todo_app.todos (id, title) VALUES ('{todo_id}', '{title}')"
rds_client.execute_statement(resourceArn='...', secretArn='...', database='demo', sql=sql)
return {"statusCode": 201, "body": json.dumps({"id": todo_id})}
Test Event JSON: {"title": "Write my blog post"}
3. Update Todo (PUT/PATCH)
# SQL: f"UPDATE todo_app.todos SET completed = {str(event['completed']).lower()} WHERE id = '{event['id']}'"
Test Event JSON: {"id": "YOUR_ID", "completed": true}
Part 4: Permissions (IAM Role)
Your Lambdas need permission to talk to the DB and the Secrets Manager.
-
Go to the IAM Console -> Roles -> Create role.
-
Select Lambda as the service.
-
Attach these policies:
-
AWSLambdaBasicExecutionRole(for logs). -
AmazonRDSDataFullAccess(to run SQL). -
Custom Inline Policy: Allow
secretsmanager:GetSecretValuefor your specific Secret ARN.
-
Conclusion
You now have a fully functional, serverless CRUD API running on AWS! This architecture is incredibly powerful because you only pay for the seconds your code runs and the small amount of database capacity used.
Thanks for tuning in! Another AWS service is now in your toolkit. If you run into trouble, feel free to reach out: 👉 Contact Me 📺 Watch the Video Tutorial
Happy coding till we meet again!! Bye bye!