[guía] deploy de lambda con typescript y sam
Inicializando el proyecto
Comenzamos con la estructura básica de un proyecto Node.js:
npm init -y
Instalación de dependencias
Producción:
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb zod
Desarrollo:
npm install -D @types/aws-lambda @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser esbuild eslint typescript
Estructura de carpetas
Creamos una estructura simple y organizada:
.
├── src/
│ ├── functions/
│ │ └── reservations.ts
│ └── utils/
│ └── response.ts
├── dist/ # Output de TypeScript
├── events/ # Para pruebas locales
├── template.yaml # CloudFormation template
├── samconfig.toml # Configuración de SAM
├── tsconfig.json
└── package.json
Configuración de TypeScript
Creamos tsconfig.json con configuración para Lambda:
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node",
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Y añadimos el script de build en package.json:
{
"scripts": {
"build": "tsc"
}
}
Template CloudFormation con SAM
Creamos un template.yaml simple con API Gateway HTTP y una Lambda:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: The dog farm API - Serverless Backend
Globals:
Function:
Runtime: nodejs22.x
Timeout: 30
MemorySize: 512
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Resources:
# API Gateway HTTP
Api:
Type: AWS::Serverless::HttpApi
Properties:
StageName: !Ref Environment
CorsConfiguration:
AllowOrigins:
- "*"
AllowMethods:
- GET
- POST
- PUT
- DELETE
# Lambda Function
ReservationsFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub the-dog-farm-reservations-${Environment}
CodeUri: dist/
Handler: functions/reservations.handler
Events:
GetReservations:
Type: HttpApi
Properties:
ApiId: !Ref Api
Path: /reservations
Method: GET
Outputs:
ApiUrl:
Description: The URL of the API Gateway
Value: !Sub https://${Api}.execute-api.${AWS::Region}.amazonaws.com/${Environment}
Puntos clave del template:
Transform: AWS::Serverless-2016-10-31activa la sintaxis SAMCodeUri: dist/apunta al código compilado de TypeScriptHandler: functions/reservations.handlersigue el formatoarchivo.función- Los
Eventsconectan automáticamente API Gateway con Lambda
Utilidad de respuesta
Primero creamos una función helper en src/utils/response.ts para estandarizar las respuestas:
export const response = (statusCode: number, body: any) => {
return {
statusCode,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: statusCode === 204 ? '' : JSON.stringify(body),
};
}
Esta función nos ahorra repetir código y garantiza que todas las respuestas tengan:
- Headers CORS configurados
- Content-Type JSON
- Body serializado (excepto para 204 No Content)
Handler de Lambda
Creamos un handler simple en src/functions/reservations.ts:
import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda';
import { response } from "../utils/response"
export const handler = async (
event: APIGatewayProxyEventV2
): Promise<APIGatewayProxyResultV2> => {
console.log('Reservation handler event', JSON.stringify(event, null, 2))
try {
const method = event.requestContext.http.method;
if (method === 'GET') {
return response(200, {
message: 'reservations is running'
})
}
return response(405, {
message: 'Method Not Allowed'
})
} catch (error) {
console.error('Error:', error);
return response(500, {
error: 'Internal server error',
message: error instanceof Error ? error.message : 'Unknown error',
});
}
}
Compilación y validación
Compilamos TypeScript a JavaScript:
npm run build
Esto genera el código en dist/ que Lambda ejecutará.
Validamos el template de CloudFormation:
sam validate
Construimos el proyecto con SAM:
sam build
SAM empaqueta las dependencias y prepara todo para el deploy.
Configuración con samconfig.toml
Antes del deploy, creamos un bucket S3 para almacenar los artifacts:
aws s3 mb s3://stack-thedogfarm-dev --region us-east-1
El archivo samconfig.toml centraliza la configuración de deploy por ambiente:
version = 0.1
[default.global.parameters]
capabilities = "CAPABILITY_IAM"
[dev]
[dev.deploy]
[dev.deploy.parameters]
stack_name = "the-dog-farm-api-dev"
s3_bucket = "stack-thedogfarm-dev"
s3_prefix = "thedogfarm"
region = "us-east-1"
parameter_overrides = [
"Environment=dev"
]
[prod]
[prod.deploy]
[prod.deploy.parameters]
stack_name = "the-dog-farm-api-prod"
s3_bucket = "stack-thedogfarm-prod"
s3_prefix = "thedogfarm"
region = "us-east-2"
confirm_changeset = true
parameter_overrides = [
"Environment=prod"
]
¿Cómo funciona?
[dev]y[prod]son perfiles de configuración- Cada perfil tiene su propio stack, bucket y región
parameter_overridespasa valores a losParametersdel templateconfirm_changeset = trueen prod requiere aprobación manual
Testing local
Creamos un archivo de evento de prueba en events/reservations-event.json:
{
"requestContext": {
"http": {
"method": "GET"
}
}
}
Probamos la Lambda localmente con este evento:
sam local invoke ReservationsFunction -e events/reservations-event.json
Iniciamos API Gateway localmente:
sam local start-api
Ahora podemos hacer requests a http://localhost:3000/reservations
Deploy a AWS
Deployamos usando el perfil de dev:
sam deploy --config-env dev
SAM:
- Sube el código al bucket S3
- Crea/actualiza el CloudFormation stack
- Despliega API Gateway y Lambda
- Muestra la URL del API en los Outputs
Para producción:
sam deploy --config-env prod
Esto usará la configuración de prod con confirmación manual del changeset.
TL;DR
# Setup
npm init -y
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb zod
npm install -D @types/aws-lambda @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser esbuild eslint typescript
# Crear estructura src/functions/ y src/utils/
# Configurar tsconfig.json y template.yaml
# Build y deploy
npm run build
sam validate
sam build
# Testing local
sam local invoke ReservationsFunction -e events/reservations-event.json
sam local start-api
# Bucket para almacenar stack
aws s3 mb s3://stack-thedogfarm-dev --region us-east-1
# Deploy
sam deploy --config-env dev
Stack completo: TypeScript → Lambda → API Gateway, configurado con SAM templates y samconfig.toml para múltiples ambientes.