You tick a todo as done · Lambda + RDS MySQL

9 steps from your browser to the database and back.

InternetAWS Region · us-east-1VPCPrivate subnet · no internetYour browseron the internetAPI GatewayHTTP API · front doorCloudWatch Logsapp log linesLambda functionruns once per requestENIfunction's network cardRDS MySQLdatabase: todoioYou tick a todo as done1Into the front door2Wake up the function3Who are you?4Step into the VPC5Ask the database6The database answers7Back to you8Leave a note9

Text version of this diagram.

What sits where:

  • AWS Region · us-east-1: A Region is a part of the world where AWS has data centers. Most things you build live in one Region. us-east-1 is in northern Virginia. contains:
    • VPC: Virtual private cloud: your own private network inside AWS. Nothing gets in or out except the ways you allow. contains:
      • Private subnet · no internet: A slice of the VPC with no route to the internet at all. Nothing here can be reached from outside. contains:
        • ENI (function's network card): Elastic network interface: a virtual network card. It gives the function an address inside your VPC.
        • RDS MySQL (database: todoio): A MySQL database that AWS runs for you, including the server, patches and backups. todoio is the database's name.
    • API Gateway (HTTP API · front door): The front door for the app's web requests: it receives each one and hands it to your code. An HTTP API is its simple kind for ordinary requests.
    • CloudWatch Logs (app log lines): Collects the lines your app writes about what it's doing (its logs), so you can search them later.
    • Lambda function (runs once per request): Code that AWS runs only when a request arrives. No server to look after, and you pay per request.
  • Your browser (on the internet)

Steps, in order:

  1. You tick a todo as done. Path: Your browser. Your browser sends PATCH /todos/42 over HTTPS.
  2. Into the front door. Path: Your browser → API Gateway. The request arrives at API Gateway, a managed HTTPS front door. There's no server or firewall for you to look after.
  3. Wake up the function. Path: API Gateway → Lambda function. API Gateway invokes your Lambda function and hands it the request as an event. Checks: iam: Lambda resource policy: API Gateway may invoke todo-api → allow.
  4. Who are you?. Path: Lambda function. The app checks your signed session cookie and finds your user id, u-123. This is the app's own login, not AWS.
  5. Step into the VPC. Path: Lambda function → ENI. The database lives in a private subnet of a VPC, so the function is attached to that VPC. AWS gives it an ENI (a network card) in the private subnet.
  6. Ask the database. Path: ENI → RDS MySQL. The app sends SQL to RDS MySQL in the private subnet on port 3306. It logs in with a database username and password, not with IAM. Checks: security-group: todo-db-sg: TCP 3306 from todo-lambda-sg → allow; mysql: MySQL user todo_app: UPDATE on todoio.todos → allow.
  7. The database answers. Path: RDS MySQL → ENI → Lambda function. MySQL says: 1 row changed.
  8. Back to you. Path: Lambda function → API Gateway → Your browser. You get 200 OK, and the todo shows a tick.
  9. Leave a note. Path: Lambda function → CloudWatch Logs. Lambda sends what the function printed to CloudWatch Logs, so Todo.io's engineers can see what happened.
Step 1 of 9
Step 1 of 9
  1. Your browser sends PATCH /todos/42 over HTTPS.

    Show me the real thing

    The HTTP request

    PATCH /todos/42 HTTP/1.1
    Host: abc123.execute-api.us-east-1.amazonaws.com
    Cookie: session=eyJ1c2VySWQiOiJ1LTEyMyJ9.Zm9v
    Content-Type: application/json
    
    {"done":true}
  2. The request arrives at API Gateway, a managed HTTPS front door. There's no server or firewall for you to look after.

  3. API Gateway invokes your Lambda function and hands it the request as an event.

    • 🔑IAM Lambda resource policy: API Gateway may invoke todo-apiAllowed
    Show me the real thing

    Resource-based policy on the function: who may call it

    {
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:111122223333:function:todo-api",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:111122223333:abc123/*"
        }
      }
    }

    Exam tipThis is a resource-based policy. It lives on the function and says who may call it, the opposite of a policy attached to a role.

  4. The app checks your signed session cookie and finds your user id, u-123. This is the app's own login, not AWS.

  5. The database lives in a private subnet of a VPC, so the function is attached to that VPC. AWS gives it an ENI (a network card) in the private subnet.

    Exam tipA Lambda ENI never gets a public IP, so a VPC-attached function can't reach the internet, even from a public subnet. It needs a NAT gateway. Classic exam trap.

  6. The app sends SQL to RDS MySQL in the private subnet on port 3306. It logs in with a database username and password, not with IAM.

    • 🛡Security group todo-db-sg: TCP 3306 from todo-lambda-sgAllowed
    • 🗄MySQL MySQL user todo_app: UPDATE on todoio.todosAllowed
    Show me the real thing

    The SQL (real code sends the values as parameters, never pasted into the string)

    UPDATE todos SET done = true WHERE id = 42 AND user_id = 'u-123';

    Exam tipA security group rule can use another security group as its source: "anything wearing todo-lambda-sg may connect". Exam favourite.

  7. MySQL says: 1 row changed.

  8. You get 200 OK, and the todo shows a tick.

    Show me the real thing

    The HTTP response

    HTTP/1.1 200 OK
  9. Lambda sends what the function printed to CloudWatch Logs, so Todo.io's engineers can see what happened.

    Show me the real thing

    The log line

    2026-10-11T18:42:07Z INFO PATCH /todos/42 user=u-123 status=200 14ms

    Exam tipLambda sends whatever your function prints to CloudWatch Logs automatically, as long as the execution role allows logs:PutLogEvents.

What to notice

  • There is no server at all. API Gateway takes the request and Lambda runs your code only when one arrives.
  • IAM never checked your SQL. MySQL has its own users; IAM only manages the database server itself.
  • The database sits in a private subnet with no route to the internet. Only the security groups you allowed can reach it.
  • The database password lives in the app config here. In production it belongs in Secrets Manager (Level 1).
  • To reach a database in a VPC, the function had to be attached to that VPC.
  • Every Lambda copy opens its own MySQL connection, and a traffic spike can exhaust them. RDS Proxy pools connections (Level 2).
  • You, the customer, were never an IAM user. IAM controls the app, not its customers.