Funciones Serverless en TypeScript: Guía completa de AWS Lambda
La arquitectura Serverless ha revolucionado el enfoque del desarrollo backend. En lugar de gestionar servidores, los desarrolladores pueden centrarse exclusivamente en la lógica de negocio. AWS Lambda es uno de los servicios más populares para ejecutar funciones serverless. En esta guía, analizaremos la creación, configuración y despliegue de funciones Lambda en TypeScript, desde conceptos básicos hasta soluciones de producción.
¿Por qué TypeScript para AWS Lambda?
TypeScript añade tipado estático a JavaScript, lo cual es críticamente importante para las funciones serverless:
- Seguridad de tipos — previene errores en la etapa de compilación
- Autocompletado — el IDE sugiere métodos del AWS SDK
- Legibilidad — las interfaces y tipos documentan la estructura de datos
- Escalabilidad — es más fácil mantener el código a medida que el proyecto crece
Configuración del proyecto
1. Inicialización e instalación de dependencias
Cree un nuevo proyecto e instale los paquetes necesarios:
mkdir my-lambda-projectcd my-lambda-projectnpm init -y
npm install @types/aws-lambda aws-sdknpm install -D typescript ts-node @types/node2. Configuración de TypeScript
Cree el archivo tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"]}Creación de la primera función Lambda
Estructura básica del handler
Cree el archivo src/handler.ts:
import { Handler, APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
interface UserData { userId: string; name: string; email: string;}
export const handler: Handler<APIGatewayProxyEvent, APIGatewayProxyResult> = async (event) => { try { // Parseo del cuerpo de la solicitud const body: UserData = JSON.parse(event.body || '{}'); // Validación if (!body.userId || !body.name) { return { statusCode: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ error: 'Faltan campos obligatorios' }) }; }
// Lógica de negocio const result = { id: body.userId, displayName: body.name.toUpperCase(), createdAt: new Date().toISOString() };
return { statusCode: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify(result) }; } catch (error) { console.error('Error al procesar la solicitud:', error); return { statusCode: 500, body: JSON.stringify({ error: 'Error interno del servidor' }) }; }};Trabajo con entorno y secretos
Utilice variables de entorno para la configuración:
import { Handler } from 'aws-lambda';
interface Config { DB_TABLE: string; MAX_RETRIES: number;}
export const handler: Handler = async (event) => { const config: Config = { DB_TABLE: process.env.DB_TABLE || 'tabla-por-defecto', MAX_RETRIES: parseInt(process.env.MAX_RETRIES || '3', 10) };
// Utilice AWS Secrets Manager o Parameter Store // para datos sensibles return { statusCode: 200, body: JSON.stringify({ table: config.DB_TABLE }) };};