Lambda
02 / 08

Event Sources & Triggers

Event Sources & Triggers

Lambda integrates with virtually every AWS service. The event payload structure varies by source — knowing the shape of the event object for each trigger is critical for writing correct handler code.

API Gateway & S3

// API Gateway HTTP API (payload format version 2.0) event shape
{
  "version": "2.0",
  "routeKey": "POST /users",
  "rawPath": "/users",
  "rawQueryString": "page=1",
  "headers": { "content-type": "application/json", ... },
  "queryStringParameters": { "page": "1" },
  "pathParameters": { "userId": "123" },
  "body": "{"name": "Alice"}",  // string, not parsed
  "isBase64Encoded": false,
  "requestContext": {
    "accountId": "123456789012",
    "http": { "method": "POST", "path": "/users", "sourceIp": "1.2.3.4" },
    "requestId": "abc-123"
  }
}

// Handler parsing API GW HTTP API event
export const handler = async (event) => {
  const body = JSON.parse(event.body || "{}");
  const userId = event.pathParameters?.userId;
  const page = parseInt(event.queryStringParameters?.page || "1", 10);
  // ...
  return { statusCode: 201, body: JSON.stringify({ id: "new-user-id" }) };
};

// S3 event — triggered on object create/delete
{
  "Records": [{
    "eventSource": "aws:s3",
    "eventName": "ObjectCreated:Put",
    "s3": {
      "bucket": { "name": "my-bucket" },
      "object": {
        "key": "uploads/image.png",   // URL-encoded — decode before use
        "size": 102400
      }
    }
  }]
}

// S3 handler
export const handler = async (event) => {
  for (const record of event.Records) {
    const bucket = record.s3.bucket.name;
    const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, " "));
    console.log(`Processing s3://${bucket}/${key}`);
    // process image, extract metadata, etc.
  }
};

SQS, SNS & DynamoDB Streams

// SQS event — batch of messages (up to 10 by default)
{
  "Records": [{
    "messageId": "abc-123",
    "body": "{"orderId": "order-456"}",   // string, must be parsed
    "attributes": {
      "ApproximateReceiveCount": "1",
      "SentTimestamp": "1703001600000"
    },
    "receiptHandle": "AQEBxxx..."    // Used to delete message (Lambda does this automatically on success)
  }]
}

// SQS handler with partial batch failure reporting
export const handler = async (event) => {
  const failures = [];
  for (const record of event.Records) {
    try {
      const payload = JSON.parse(record.body);
      await processOrder(payload.orderId);
    } catch (err) {
      console.error("Failed:", record.messageId, err);
      failures.push({ itemIdentifier: record.messageId });
    }
  }
  // Return failed message IDs — Lambda will requeue only these
  return { batchItemFailures: failures };
};
// Enable "Report batch item failures" in the SQS event source mapping

// SNS event — Lambda subscribed to a topic
{
  "Records": [{
    "EventSource": "aws:sns",
    "Sns": {
      "Message": "{"type": "user.created", "userId": "123"}",
      "Subject": "User Event",
      "TopicArn": "arn:aws:sns:us-east-1:123:my-topic"
    }
  }]
}

// DynamoDB Streams — process table changes
{
  "Records": [{
    "eventSource": "aws:dynamodb",
    "eventName": "INSERT",   // INSERT | MODIFY | REMOVE
    "dynamodb": {
      "Keys": { "pk": { "S": "USER#123" } },
      "NewImage": { "pk": { "S": "USER#123" }, "name": { "S": "Alice" } },
      "OldImage": null   // null for INSERT
    }
  }]
}

EventBridge & Step Functions

# EventBridge — serverless event bus
# Schedule a Lambda every 5 minutes (cron expression)
aws events put-rule   --name "run-every-5-min"   --schedule-expression "rate(5 minutes)"   --state ENABLED

aws lambda add-permission   --function-name my-function   --statement-id EventBridgeInvoke   --action lambda:InvokeFunction   --principal events.amazonaws.com   --source-arn arn:aws:events:us-east-1:123:rule/run-every-5-min

aws events put-targets   --rule "run-every-5-min"   --targets "Id=1,Arn=arn:aws:lambda:us-east-1:123:function:my-function"

# EventBridge event payload
# { "version": "0", "id": "...", "source": "aws.ec2", "detail-type": "EC2 Instance State-change Notification",
#   "detail": { "instance-id": "i-123", "state": "running" } }

# Step Functions — orchestrate Lambda functions
# Define a state machine in JSON/YAML (ASL — Amazon States Language)
# Lambda invoked as a Task state, receives input, returns output to next state
# Supports parallel execution, error handling, wait states, and human approval steps

# Kinesis Data Streams — real-time streaming
# Lambda reads batches of records from a Kinesis shard
# Records contain base64-encoded data
# export const handler = async (event) => {
#   for (const record of event.Records) {
#     const data = Buffer.from(record.kinesis.data, "base64").toString("utf-8");
#     const payload = JSON.parse(data);
#     await processMetric(payload);
#   }
# };

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free