Guía
Cómo diseñar una pequeña API de producción
Un proyecto inicial de producción no necesita decenas de abstracciones. Necesita un límite de proceso claro, una configuración predecible y suficientes señales para operar con seguridad.
La primera versión de producción debe ser lo suficientemente pequeña para entender bajo presión.
Haz que el inicio sea determinista
Un servicio debe iniciarse con un único comando documentado, escuchar en el puerto configurado y fallar con un error útil si falta configuración necesaria. Evita configuraciones que dependan de archivos o del estado del shell fuera del repositorio y el manifiesto.
Ejecuta las migraciones de esquema como un paso explícito de publicación cuando el framework lo admita. Ocultar una migración destructiva en el inicio del proceso hace que todas las réplicas deban coordinar el mismo cambio de base de datos a la vez.
name: orders-api
build_cmd: npm ci && npm run build
start_cmd: node dist/server.js
runtime:
name: node@24
port: 8080
health_path: /healthzMantén visible la ruta de la solicitud
Empieza con una capa de rutas ligera, código de dominio que se pueda probar sin HTTP y un pequeño adaptador para cada dependencia externa. Añade una cola, caché o segundo servicio solo cuando la carga de trabajo lo justifique.
Devuelve estructuras de error coherentes e identificadores de solicitud. El identificador debe propagarse por los registros y llamadas salientes para seguir una solicitud fallida sin depender solo de la marca de tiempo.
- —Capa de rutas: analiza la entrada HTTP y convierte los errores de dominio en respuestas estables.
- —Función de dominio: aplica las reglas de pedidos sin depender del framework web.
- —Adaptador del repositorio: controla SQL y los límites de transacción.
- —Adaptador del proveedor: aplica límites de tiempo y traduce los fallos externos.
Publica con señales operativas
Como mínimo, expón la disponibilidad para atender solicitudes, escribe registros estructurados y gestiona el cierre con tiempo suficiente para terminar o rechazar limpiamente las solicitudes en curso. Aplica límites de tiempo a las llamadas salientes y límites de recursos que revelen fugas antes de afectar a cargas vecinas.
Estas decisiones son modestas, pero crean un servicio que el equipo puede depurar. Añade arquitectura cuando la aplicación lo justifique, no porque el proyecto inicial tenga sitio para otra carpeta.
const close = async (signal) => {
app.log.info({ signal }, "shutdown started");
await app.close();
await database.end();
process.exit(0);
};
process.once("SIGTERM", () => close("SIGTERM"));
process.once("SIGINT", () => close("SIGINT"));Prueba un fallo completo
Antes de considerar que el servicio está listo para producción, elige una dependencia y provoca su fallo. Para la API de pedidos, detén PostgreSQL mientras envías solicitudes. Los nuevos pedidos deben fallar con una respuesta 503 acotada, la comprobación de disponibilidad debe retirar la réplica de la rotación y los registros deben conservar el ID de solicitud sin imprimir la cadena de conexión.
Restaura PostgreSQL y confirma que el servicio vuelve a estar disponible sin pedidos duplicados. Ese ejercicio prueba más del contrato operativo real que un gran conjunto de pruebas unitarias limitadas a rutas.