Guía práctica de AWS Lambda con Claude Code: Node.js, IAM y API Gateway
Crea una Lambda Node.js con Claude Code: pruebas locales, IAM de mínimo privilegio, variables, API Gateway y logs.
Claude Code acelera mucho el trabajo con AWS Lambda porque puede preparar en una misma sesión el handler, el evento de prueba, un borrador de IAM, los comandos de despliegue y una checklist de revisión. Esa velocidad es útil, pero los permisos y los costes de AWS son decisiones reales de producción. Usa Claude Code para redactar y revisar; no para conceder permisos, publicar APIs o crear recursos facturables sin revisión humana.
Esta guía muestra un flujo práctico para equipos: crear una Lambda con Node.js, probarla en local, acercar IAM al mínimo privilegio, configurar variables de entorno, conectar API Gateway, leer CloudWatch Logs, actualizar el paquete zip y cerrar el ciclo con una revisión segura. Lambda es un runtime pequeño que se ejecuta cuando llega un evento. IAM es el modelo de permisos que decide qué puede hacer la función. API Gateway es la puerta HTTP que envía peticiones a Lambda.
Conviene tener abiertas las referencias oficiales: introducción a AWS Lambda, Lambda con Node.js, variables de entorno en Lambda, monitorización con CloudWatch Logs y Claude Code common workflows. Los ejemplos usan el runtime Node.js 24 de Lambda, vigente para este artículo el 1 de junio de 2026.
Cuándo usar este patrón
Lambda encaja cuando necesitas una acción pequeña y fiable sin mantener un servidor encendido todo el día. Claude Code aporta más valor cuando genera una estructura repetible y una persona conserva la decisión final.
| Caso de uso | Por qué encaja Lambda | Qué puede redactar Claude Code | Qué debe revisar una persona |
|---|---|---|---|
| Recepción de webhooks | Pagos, formularios y SaaS envían eventos breves | Validación de firma, fixtures, respuestas de error | Secretos, reintentos, duplicados |
| API JSON interna | Un endpoint pequeño no necesita servidor permanente | Handler, comandos de API Gateway, formato de logs | Autenticación, CORS, exposición, coste |
| Entrada de batch | CSV, imágenes y notificaciones pueden empezar pequeño | Validación, logs estructurados, clases de error | Timeout, estrategia de reintento, borrado seguro |
Para una primera prueba, AWS CLI más un paquete zip es rápido. Para operación de equipo, migra después a SAM, CDK u otro flujo IaC revisado.
| Método | Mejor para | Cuidado con |
|---|---|---|
| Consola AWS | Ver un comportamiento una vez | Los pasos manuales no quedan en revisión |
| AWS CLI + zip | Prueba pequeña y reproducible | IAM y variables requieren revisión |
| SAM / CDK | Operación continua en equipo | IaC y aprobaciones de despliegue son obligatorias |
flowchart LR
A[Borrador con Claude Code] --> B[Prueba local con Node.js]
B --> C[Revisión humana de IAM y entorno]
C --> D[Zip package a dev]
D --> E[Prueba con API Gateway]
E --> F[Lectura de CloudWatch Logs]
F --> A
1. Crear el handler Node.js
Empieza con un index.mjs sin dependencias externas. Acepta eventos HTTP API v2 y también el formato más antiguo de REST API.
// index.mjs
import crypto from "node:crypto";
const allowedStages = new Set(["dev", "staging", "prod"]);
function readConfig() {
const stage = process.env.APP_STAGE ?? "dev";
if (!allowedStages.has(stage)) {
throw new Error(`Invalid APP_STAGE: ${stage}`);
}
return {
stage,
tableName: process.env.TABLE_NAME ?? "local-orders",
logLevel: process.env.LOG_LEVEL ?? "info",
};
}
function log(level, message, details = {}) {
console.log(
JSON.stringify({
level,
message,
service: "orders-api",
...details,
})
);
}
function json(statusCode, body) {
return {
statusCode,
headers: {
"content-type": "application/json",
},
body: JSON.stringify(body),
};
}
function parseBody(event) {
if (!event.body) return {};
const raw = event.isBase64Encoded
? Buffer.from(event.body, "base64").toString("utf8")
: event.body;
return JSON.parse(raw);
}
export async function handler(event = {}, context = {}) {
const config = readConfig();
const method = event.requestContext?.http?.method ?? event.httpMethod ?? "GET";
const path = event.rawPath ?? event.path ?? "/";
const requestId = context.awsRequestId ?? "local";
log("info", "request.start", {
requestId,
method,
path,
stage: config.stage,
});
try {
if (method === "GET" && path === "/health") {
return json(200, { ok: true, stage: config.stage });
}
if (method === "POST" && path === "/orders") {
const payload = parseBody(event);
const orderId = payload.orderId ?? crypto.randomUUID();
log("info", "order.accepted", {
requestId,
orderId,
tableName: config.tableName,
});
return json(202, {
orderId,
status: "accepted",
storedIn: config.tableName,
});
}
return json(404, { error: "not_found", method, path });
} catch (error) {
log("error", "request.failed", {
requestId,
errorName: error.name,
errorMessage: error.message,
});
return json(500, { error: "internal_error", requestId });
}
}
Todavía no escribe en DynamoDB. Es intencional: primero confirma recepción del evento, parseo de JSON, forma de la respuesta y logs buscables. La base de datos y sus permisos deben llegar después.
2. Probar en local con un fixture de evento
Un fixture es una entrada fija de prueba. Aunque Claude Code lo genere, guárdalo en el repositorio para que la revisión sea reproducible.
{
"version": "2.0",
"routeKey": "POST /orders",
"rawPath": "/orders",
"requestContext": {
"http": {
"method": "POST",
"path": "/orders"
}
},
"headers": {
"content-type": "application/json"
},
"body": "{\"orderId\":\"demo-1001\",\"amount\":3200,\"currency\":\"JPY\"}",
"isBase64Encoded": false
}
Guárdalo como events/create-order.json y añade un runner local.
// local-test.mjs
import { readFile } from "node:fs/promises";
import { handler } from "./index.mjs";
process.env.APP_STAGE = "dev";
process.env.TABLE_NAME = "orders-dev";
process.env.LOG_LEVEL = "debug";
const eventPath = process.argv[2] ?? "events/create-order.json";
const event = JSON.parse(await readFile(eventPath, "utf8"));
const result = await handler(event, { awsRequestId: "local-001" });
console.log(JSON.stringify(result, null, 2));
Ejecuta antes de tocar AWS:
node local-test.mjs events/create-order.json
Si no devuelve statusCode: 202, desplegar solo hará el diagnóstico más lento. Un fixture concreto también permite que Claude Code razone sobre una entrada real, no sobre suposiciones.
3. Mantener IAM cerca del mínimo privilegio
No adjuntes AdministratorAccess al execution role. Empieza con logs y agrega acceso a datos solo cuando el handler lo use.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CreateOwnLogGroupIfMissing",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:ap-northeast-1:123456789012:*"
},
{
"Sid": "WriteOwnLambdaLogs",
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/claude-orders-dev:*"
},
{
"Sid": "ReadWriteOnlyOrdersTable",
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:Query"],
"Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/orders-dev"
}
]
}
Esto es un borrador, no una respuesta de producción. Cambia cuenta, región, función y tabla; elimina el bloque de DynamoDB hasta que realmente lo uses. Para revisar permisos, consulta también la guía de AWS IAM.
4. Desplegar un paquete zip con AWS CLI
Los siguientes comandos crean recursos reales de AWS y pueden generar coste. Usa una cuenta dev, confirma región y prepara limpieza antes de ejecutar.
export AWS_REGION=ap-northeast-1
export FUNCTION_NAME=claude-orders-dev
export ROLE_NAME=claude-orders-dev-lambda-role
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
zip function.zip index.mjs
Crea trust-policy.json para que Lambda pueda asumir el role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Guarda el borrador IAM anterior como lambda-policy.json y crea role y función.
aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document file://trust-policy.json
aws iam put-role-policy \
--role-name "$ROLE_NAME" \
--policy-name claude-orders-dev-inline \
--policy-document file://lambda-policy.json
ROLE_ARN=$(aws iam get-role \
--role-name "$ROLE_NAME" \
--query "Role.Arn" \
--output text)
aws lambda create-function \
--function-name "$FUNCTION_NAME" \
--runtime nodejs24.x \
--handler index.handler \
--zip-file fileb://function.zip \
--role "$ROLE_ARN" \
--architectures arm64 \
--timeout 10 \
--memory-size 128 \
--environment "Variables={APP_STAGE=dev,TABLE_NAME=orders-dev,LOG_LEVEL=info}" \
--region "$AWS_REGION"
Para actualizar solo el código:
zip function.zip index.mjs
aws lambda update-function-code \
--function-name "$FUNCTION_NAME" \
--zip-file fileb://function.zip \
--region "$AWS_REGION"
Cuidado con las variables de entorno. Con update-function-configuration, el mapa Variables se reemplaza completo. Lee la configuración actual antes de modificarla. Las claves y contraseñas deberían ir en Secrets Manager o Parameter Store, no como texto plano.
aws lambda update-function-configuration \
--function-name "$FUNCTION_NAME" \
--environment "Variables={APP_STAGE=dev,TABLE_NAME=orders-dev,LOG_LEVEL=debug}" \
--region "$AWS_REGION"
5. Verificar API Gateway y CloudWatch Logs
Primero invoca Lambda directamente.
aws lambda invoke \
--function-name "$FUNCTION_NAME" \
--payload fileb://events/create-order.json \
--region "$AWS_REGION" \
response.json
cat response.json
Después crea una HTTP API. Esto expone un endpoint público, así que revisa auth, CORS, límites y limpieza antes de ejecutarlo.
API_ID=$(aws apigatewayv2 create-api \
--name claude-orders-dev-api \
--protocol-type HTTP \
--target "arn:aws:lambda:${AWS_REGION}:${ACCOUNT_ID}:function:${FUNCTION_NAME}" \
--query "ApiId" \
--output text)
aws lambda add-permission \
--function-name "$FUNCTION_NAME" \
--statement-id AllowHttpApiInvoke \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:${AWS_REGION}:${ACCOUNT_ID}:${API_ID}/*/*" \
--region "$AWS_REGION"
API_ENDPOINT=$(aws apigatewayv2 get-api \
--api-id "$API_ID" \
--query "ApiEndpoint" \
--output text)
curl -s "$API_ENDPOINT/health"
curl -s -X POST "$API_ENDPOINT/orders" \
-H "content-type: application/json" \
-d '{"amount":3200,"currency":"JPY"}'
Mira los logs justo después.
aws logs tail "/aws/lambda/${FUNCTION_NAME}" \
--follow \
--region "$AWS_REGION"
Si no aparecen logs, revisa región, nombre de función, logs:CreateLogStream y logs:PutLogEvents. Si API Gateway devuelve 500, confirma que la respuesta tenga statusCode, headers y body. Para profundizar, lee la guía de AWS CloudWatch y la guía de AWS API Gateway.
Prompt de Claude para revisar Lambda
Haz que Claude Code explique el riesgo antes de editar o desplegar.
You are reviewing a Node.js AWS Lambda change for a team repository.
Scope:
- Files: index.mjs, events/*.json, IAM policy JSON, deployment commands in docs
- Runtime: nodejs24.x
- Entry point: index.handler
Review for:
1. API Gateway event compatibility and response shape
2. Input validation and JSON parsing failures
3. Environment variables that overwrite existing values
4. IAM actions that are wider than needed
5. CloudWatch logs that expose secrets or personal data
6. AWS resources that can create unexpected cost
7. Local test commands that a reviewer can copy and run
Return:
- blocking issues
- non-blocking improvements
- exact commands to verify locally
- questions a human must answer before deploying
El ciclo seguro es: explorar, planificar, editar, probar localmente, desplegar solo a dev, leer logs y pedir aprobación humana para IAM y costes. Para pasar este proof of concept a CI/CD e IaC, sigue con la guía de deployment en AWS.
Errores frecuentes
El primero es desplegar sin reproducción local. Si el evento tiene una forma incorrecta, un fixture lo descubre antes que CloudWatch.
El segundo es poner secretos directamente en variables de entorno. Son útiles para configuración, pero los secretos necesitan control de acceso y rotación.
El tercero es abrir demasiado IAM. dynamodb:* y Resource: "*" hacen que una demo funcione, pero amplían el impacto de un error.
El cuarto es exponer API Gateway sin responsable claro. Antes de compartir la URL decide autenticación, CORS, throttling, logs y fecha de limpieza.
El quinto es olvidar costes. Lambda parece pequeño, pero API Gateway, CloudWatch Logs, DynamoDB, NAT y llamadas externas también cobran.
ClaudeCodeLab reúne este tipo de flujo en templates y material de formación de Claude Code. Si tu equipo necesita diseñar permisos AWS, CLAUDE.md, prompts de revisión y reglas de aprobación de despliegue sobre un repositorio real, revisa la página de consultoría y formación de Claude Code.
Elimina los recursos de prueba cuando termines.
aws apigatewayv2 delete-api --api-id "$API_ID" --region "$AWS_REGION"
aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$AWS_REGION"
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name claude-orders-dev-inline
aws iam delete-role --role-name "$ROLE_NAME"
Al probar el flujo de este artículo, el mayor beneficio fue que Claude Code mantuvo handler, fixture, borrador IAM y comandos CLI en un mismo contexto revisable. La parte peligrosa no fue generar código, sino decidir permisos y exposición. El patrón fiable es fixture local primero, despliegue dev después, evidencia en CloudWatch y revisión humana de IAM y costes antes de acercarse a producción.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.