Procesamiento de Pagos Seguro y Escalable con Stripe, AWS Lambda y DynamoDB
Este tutorial te guía paso a paso en el diseño y despliegue de una plataforma de comercio electrónico totalmente serverless capaz de procesar pagos en tiempo real con alta disponibilidad, garantizando la seguridad de los datos sensibles y el almacenamiento eficiente de las transacciones.
Introducción al Procesamiento de Pagos Serverless
El comercio electrónico moderno exige arquitecturas capaces de responder instantáneamente ante picos de tráfico inesperados, sin descuidar la seguridad de la información financiera y optimizando los costos operativos. La computación serverless se ha convertido en el estándar de la industria para cumplir con estos requisitos, eliminando la necesidad de aprovisionar y administrar servidores tradicionales.
En este tutorial avanzado, implementaremos una solución completa para procesar pagos utilizando AWS Lambda como motor de ejecución, Amazon DynamoDB para el registro persistente de transacciones y la pasarela de pagos Stripe para gestionar de manera segura las tarjetas de crédito y las transacciones monetarias.
Arquitectura del Sistema
Antes de escribir código, es fundamental comprender cómo fluyen los datos entre el cliente, la API Gateway, nuestras funciones Lambda y los servicios externos como Stripe.
Componentes Clave
- API Gateway: El punto de entrada HTTP que expone nuestros endpoints seguros para el procesamiento de pagos.
- AWS Lambda (Node.js): Contiene la lógica de negocio para validar las peticiones, comunicarse con Stripe y registrar los resultados.
- Amazon DynamoDB: Base de datos NoSQL con diseño de clave de partición y ordenamiento para almacenar el historial de transacciones de manera ultrarrápida.
- Stripe SDK: La biblioteca oficial que gestiona de forma segura los tokens de pago y las llamadas a la pasarela.
Preparación del Entorno de Desarrollo
Para seguir este tutorial con éxito, asegúrate de cumplir con los siguientes requisitos previos:
Instalación de Dependencias
Crea un nuevo directorio para tu proyecto e inicializa un proyecto Node.js:
mkdir serverless-payment-gateway
cd serverless-payment-gateway
npm init -y
A continuación, instala las dependencias necesarias para interactuar con Stripe y el SDK de AWS:
npm install stripe @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb uuid
npm install --save-dev serverless
Configuración de la Base de Datos con DynamoDB
Una gestión eficiente de los datos de pago requiere una tabla optimizada. Utilizaremos Amazon DynamoDB para almacenar cada intento de pago utilizando un identificador único (UUID).
Estructura de la Tabla
- Nombre de la tabla:
Transactions - Clave de partición:
transactionId(String) - Atributos adicionales:
userId,amount,currency,status,createdAt
Puedes desplegar esta tabla utilizando un archivo de configuración de Serverless Framework (serverless.yml). Creemos este archivo en la raíz del proyecto:
service: serverless-payment-gateway
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
environment:
STRIPE_SECRET_KEY: ${env:STRIPE_SECRET_KEY}
TRANSACTIONS_TABLE: ${self:custom.transactionsTable}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
- dynamodb:UpdateItem
Resource:
- Fn::GetAtt: [TransactionsTable, Arn]
custom:
transactionsTable: transactions-table-${sls:stage}
functions:
processPayment:
handler: handler.processPayment
events:
- httpApi:
path: /pay
method: post
resources:
Resources:
TransactionsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.transactionsTable}
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: transactionId
AttributeType: S
KeySchema:
- AttributeName: transactionId
KeyType: S
Desarrollo de la Función Lambda para Procesar el Pago
El núcleo de nuestra aplicación reside en la función Lambda. Esta función recibirá los datos del cliente y el monto, se comunicará con Stripe para realizar el cargo y finalmente guardará el registro en DynamoDB.
Crea un archivo llamado handler.js con el siguiente código:
const { v4: uuidv4 } = require('uuid');
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
const client = new DynamoDBClient({});
const dynamoDb = DynamoDBDocumentClient.from(client);
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const TRANSACTIONS_TABLE = process.env.TRANSACTIONS_TABLE;
module.exports.processPayment = async (event) => {
try {
const body = JSON.parse(event.body);
const { amount, currency, paymentMethodId, customerId } = body;
if (!amount || !currency || !paymentMethodId) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Faltan parámetros obligatorios en la solicitud' }),
};
}
// 1. Crear el cargo utilizando Stripe
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency,
payment_method: paymentMethodId,
confirm: true,
return_url: 'https://tusitio.com/checkout/complete',
});
const transactionId = uuidv4();
const timestamp = new Date().toISOString();
// 2. Preparar el objeto de transacción para DynamoDB
const transactionRecord = {
transactionId,
customerId: customerId || 'guest',
amount,
currency,
status: paymentIntent.status,
stripePaymentIntentId: paymentIntent.id,
createdAt: timestamp,
};
// 3. Guardar en DynamoDB
await dynamoDb.send(
new PutCommand({
TableName: TRANSACTIONS_TABLE,
Item: transactionRecord,
})
);
return {
statusCode: 200,
body: JSON.stringify({
message: 'Pago procesado exitosamente',
transactionId,
status: paymentIntent.status,
}),
};
} catch (error) {
console.error('Error al procesar el pago:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
Seguridad y Buenas Prácticas en Pasarelas de Pago
Cuando trabajamos con sistemas financieros, la seguridad no es opcional. Debemos cumplir estrictamente con normativas internacionales como PCI-DSS.
Recomendaciones Clave
- Gestión de Secretos: Utiliza AWS Secrets Manager o variables de entorno cifradas para almacenar tu
STRIPE_SECRET_KEY. No hardcodees credenciales en el código fuente. - Validación de Entradas: Asegúrate de validar y sanitizar todos los datos entrantes en la función Lambda antes de interactuar con la pasarela de pagos.
- Idempotencia: Implementa mecanismos de idempotencia utilizando identificadores únicos enviados desde el cliente para evitar cargos duplicados en caso de reintentos de red.
Despliegue y Pruebas de la Solución
Una vez que hayas configurado tu código y el archivo serverless.yml, es momento de desplegar la infraestructura en tu cuenta de AWS.
Pasos para el Despliegue
- Configura tu clave secreta de Stripe como variable de entorno en tu terminal:
export STRIPE_SECRET_KEY=sk_test_tu_clave_secreta_aqui
- Ejecuta el comando de despliegue mediante Serverless Framework:
npx serverless deploy --verbose
- Copia la URL de la API HTTP devuelta por la consola al finalizar el despliegue.
Probando el Endpoint con cURL
Puedes realizar una prueba simulando una petición HTTP POST utilizando curl:
curl -X POST https://tu-api-gateway-url.amazonaws.com/pay \
-H "Content-Type: application/json" \
-d '{
"amount": 2000,
"currency": "usd",
"paymentMethodId": "pm_card_visa",
"customerId": "cust_12345"
}'
Preguntas Frecuentes (FAQ)
¿Cómo manejo los webhooks de Stripe para pagos asíncronos?
Para métodos de pago que requieren confirmación adicional (como 3D Secure o transferencias bancarias), debes crear una segunda función Lambda expuesta a través de API Gateway para escuchar los eventos de webhook de Stripe (como `payment_intent.succeeded` o `payment_intent.payment_failed`) y actualizar el estado en DynamoDB de forma asíncrona.¿Qué pasa si ocurre un fallo de red durante el registro en DynamoDB después de cobrar en Stripe?
Esta es una situación crítica conocida como inconsistencia transaccional. Para mitigarla, puedes implementar una función de reconciliación nocturna utilizando AWS EventBridge y AWS Lambda que compare los cargos registrados en Stripe con los almacenados en DynamoDB, o bien utilizar transacciones distribuidas y colas de reintento con Amazon SQS.Conclusión
Has construido con éxito una arquitectura serverless robusta, escalable y segura para el procesamiento de pagos utilizando AWS Lambda, DynamoDB y Stripe. Este diseño te permite crecer desde cero transacciones hasta millones de operaciones mensuales sin preocuparte por la infraestructura subyacente, manteniendo un costo estrictamente ligado al consumo real.
Tutoriales relacionados
- Implementando Contenedores Serverless con AWS Fargate: Una Guía Detalladaintermediate25 min
- Simplificando la Integración de Datos Serverless con AWS Lambda y Amazon Kinesisintermediate20 min
- Gestionando Sesiones y Estado de Usuario en Aplicaciones Serverless con Cognito y Lambdaintermediate20 min
- Simplificando la Orquestación de Contenedores Serverless con AWS App Runner: Guía Prácticaintermediate18 min
- Construyendo Aplicaciones Multitenant Serverless con AWS Lambda y DynamoDBadvanced12 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!