You delete a todo · Lambda + RDS MySQL

12 steps from your browser to the database and back.

InternetAWS Region · us-east-1VPCPublic subnet · to IGWPrivate subnet · to NATYour browseron the internetAPI GatewayHTTP API · front doorAPI GatewayWebSocket API · live lineCloudWatch Logsapp log linesInternet gatewaythe VPC's doorLambda functionruns once per requestNAT gatewayone-way exitENIfunction's network cardRDS MySQLdatabase: todoioThe live line is already open1You delete a todo2Into the front door3Wake up the function4Who are you?5Step into the VPC6Ask the database7The database answers8Tell your other tabs9It shows up instantly10Back to you11Leave a note12

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:
      • Public subnet · to IGW: A slice of the VPC that can reach the internet directly, through the internet gateway (IGW). contains:
        • NAT gateway (one-way exit): Lets things in a private subnet start connections out to the internet, while nothing outside can start one in.
      • Private subnet · to NAT: A slice of the VPC with no door to the internet. Things here can reach out through the NAT gateway, but nothing outside can reach in. 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.
      • Internet gateway (the VPC's door): The door between a VPC and the internet. Without one, nothing in the VPC can talk to the internet directly.
    • 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.
    • API Gateway (WebSocket API · live line): The front door for the app's web requests. A WebSocket API keeps a connection open, so the server can push updates to your browser instantly.
    • 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. The live line is already open. Path: Your browser → API Gateway. When you logged in, your browser opened a WebSocket to API Gateway. It stays open, so AWS can send you messages any time.
  2. You delete a todo. Path: Your browser. Your browser sends DELETE /todos/42 over HTTPS.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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: DELETE on todoio.todos → allow.
  8. The database answers. Path: RDS MySQL → ENI → Lambda function. MySQL says: 1 row deleted.
  9. Tell your other tabs. Path: Lambda function → ENI → NAT gateway → Internet gateway → API Gateway. The app looks up your connection id in the database and posts a message to it through the WebSocket API. It's attached to the VPC with no public IP, so it gets out through a NAT gateway and the internet gateway. Checks: iam: todo-app-lambda-role: execute-api:ManageConnections → allow.
  10. It shows up instantly. Path: API Gateway → Your browser. Every Todo.io tab you have open, on any device, shows the change without a refresh.
  11. Back to you. Path: Lambda function → API Gateway → Your browser. You get 204 No Content, and the todo disappears.
  12. 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 12
Step 1 of 12
  1. When you logged in, your browser opened a WebSocket to API Gateway. It stays open, so AWS can send you messages any time.

    Show me the real thing

    The WebSocket handshake

    GET /prod HTTP/1.1
    Host: ws123.execute-api.us-east-1.amazonaws.com
    Upgrade: websocket
    Connection: Upgrade
    
    → API Gateway assigns connection id Ab3xYzEXAMPLE=

    Exam tipAn API Gateway WebSocket API has $connect, $disconnect and $default routes. Each one can call Lambda or an HTTP backend.

  2. Your browser sends DELETE /todos/42 over HTTPS.

    Show me the real thing

    The HTTP request

    DELETE /todos/42 HTTP/1.1
    Host: abc123.execute-api.us-east-1.amazonaws.com
    Cookie: session=eyJ1c2VySWQiOiJ1LTEyMyJ9.Zm9v
  3. The request arrives at API Gateway, a managed HTTPS front door. There's no server or firewall for you to look after.

  4. 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.

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

  6. 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.

  7. 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: DELETE on todoio.todosAllowed
    Show me the real thing

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

    DELETE FROM todos 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.

  8. MySQL says: 1 row deleted.

    Exam tipCloudTrail records AWS API calls like DeleteDBInstance, but it never sees the rows your SQL deletes.

  9. The app looks up your connection id in the database and posts a message to it through the WebSocket API. It's attached to the VPC with no public IP, so it gets out through a NAT gateway and the internet gateway.

    • 🔑IAM todo-app-lambda-role: execute-api:ManageConnectionsAllowed
    Show me the real thing

    Posting to a connection

    POST /prod/@connections/Ab3xYzEXAMPLE= HTTP/1.1
    Host: ws123.execute-api.us-east-1.amazonaws.com
    
    {"type":"todo.deleted","todoId":"42"}

    Exam tipA Lambda attached to a VPC needs a NAT gateway (or a VPC endpoint) to reach anything outside the VPC, even AWS services like SQS.

  10. Every Todo.io tab you have open, on any device, shows the change without a refresh.

  11. You get 204 No Content, and the todo disappears.

    Show me the real thing

    The HTTP response

    HTTP/1.1 204 No Content
  12. 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 DELETE /todos/42 user=u-123 status=204 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).
  • A WebSocket stays open, so the server side can send you updates without you asking.
  • A Lambda in a VPC can't reach public AWS services by itself, so this VPC needed a NAT gateway.
  • You, the customer, were never an IAM user. IAM controls the app, not its customers.