Inicio / Artículos

Seis patrones de integración para conectar servicios de Node.js de manera fiable

Aprenda los patrones fundamentales detrás de integraciones sólidas con Node.js: solicitud-respuesta, polling, webhooks, clave API, autenticación JWT y OAuth, reintentos con retroceso temporal, y mapeo de datos.

Editor: REACTAPP.TOP7 min de lectura1511 palabras

Fuentes: 6 API Integration Patterns Every Node.js Integration Engineer Must Know

Enviar una solicitud HTTP es sencillo; mantener una integración funcionando cuando el otro sistema es lento, está inactivo o tiene una estructura diferente es la verdadera tarea. Esta guía aborda seis patrones que se repiten cuando los servicios de Node.js se comunican con proveedores de pagos, CRM, ERP y entre sí, además de los problemas que separan una demostración de una integración fiable.

1. Solicitud-respuesta: la base síncrona

En el modelo de solicitud-respuesta, un cliente envía una solicitud, el servidor realiza el trabajo y la respuesta llega a través de la misma conexión. Este modelo cubre la mayoría de las operaciones cotidianas: iniciar sesión, crear o actualizar registros, obtener información de un cliente, eliminar un recurso.

app.get("/users/:id", async (req, res) => {
  const user = await db.findUser(req.params.id);
  res.json(user);
});

Es sencillo de depurar y constituye la opción predeterminada para operaciones CRUD. Su debilidad radica en las tareas que tardan mucho en ejecutarse: un informe extenso o un archivo grande pueden superar los tiempos de espera del cliente o del proxy. Cabe señalar también que este controlador devuelve null con el estado 200 cuando el usuario no existe; un verdadero endpoint debería responder con 404.

2. Polling: solicitar hasta que la tarea se complete

Cuando no es posible generar un resultado de inmediato, el servidor puede aceptar la tarea, devolver un identificador y permitir que el cliente verifique nuevamente. Los casos típicos incluyen esperar a que se procese un pago, se genere un informe, se transcode un video o se envíe un pedido.

Al iniciar una tarea se devuelve su ID:

POST /reports

Response:
{
  "jobId": "abc123"
}

Luego, el cliente verifica periódicamente el endpoint de estado:

GET /reports/abc123/status

hasta que la tarea indique que ha finalizado:

{
  "status": "completed"
}

El polling es sencillo y compatible con los firewalls, por lo que muchos sistemas empresariales siguen dependiendo de él. El costo radica en el tráfico desperdiciado, ya que la mayoría de las verificaciones devuelven “todavía no”. Espacie las solicitudes (respetando Retry-After si se envía), establezca un plazo general y maneje tanto los casos fallidos como los completados.

3. Webhooks: permitir que la otra parte lo llame

Los webhooks invierten la dirección. En lugar de que su servicio haga consultas repetidamente, el proveedor envía una solicitud HTTP a su endpoint cuando ocurre algo: un pago tiene éxito, se realiza un pedido, llega un mensaje, un cliente se registra o cambia el inventario. Stripe, Slack, GitHub y Shopify dependen en gran medida de este modelo.

Un receptor mínimo en Express:

app.post("/webhook/payment", (req, res) => {
  const event = req.body;

  if (event.type === "payment.success") {
    console.log("Payment received!");
  }

  res.sendStatus(200);
});

Esto muestra la estructura básica, pero un receptor para producción necesita más elementos:

  • Verifique al remitente. Cualquiera puede publicar en una URL pública. Los proveedores suelen firmar cada carga de trabajo, y usted debe verificar esa firma (generalmente en comparación con el cuerpo de la solicitud sin procesar) antes de confiar en el evento.
  • Esté preparado para duplicados. Las entregas generalmente se intentan nuevamente hasta que se confirme su recepción, por lo que el mismo evento puede llegar más de una vez. Almacene los IDs de los eventos procesados y haga que los manejadores sean idempotentes.
  • Confirme rápidamente. Devuelva un código 2xx de inmediato y aplique el trabajo lento a una cola; de lo contrario, el proveedor podría agotar su tiempo de espera y reenviarlo.

La integración basada en eventos es cada vez más preferida porque elimina el tráfico de consulta continua.

4. Autenticación: demostrar quién está realizando la llamada

Toda integración comienza con credenciales. Tres enfoques cubren la mayoría de los casos.

Claves API

El esquema más simple envía un secreto compartido en un encabezado:

GET /users

x-api-key: abc123xyz

En Node.js con axios, la clave debe provenir de la configuración, nunca del código fuente:

axios.get(url, {
  headers: {
    "x-api-key": process.env.API_KEY
  }
});

Las claves de API son adecuadas para herramientas internas e integraciones simples entre servidores. Por sí solas no tienen fecha de vencimiento ni identifican al usuario, por lo que se deben rotar y delimitar en el ámbito más restringido que permita el proveedor.

Tokens Web JSON

Los JWT permiten la autenticación sin estado. La secuencia habitual es:

  1. El usuario inicia sesión.
  2. El servidor emite un token firmado.
  3. El cliente guarda el token.
  4. Cada solicitud posterior lo incluye en un encabezado:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Emisión de uno en Node.js:

const token = jwt.sign(
  { userId: 1 },
  process.env.JWT_SECRET
);

Cualquier servicio que cuente con la clave de verificación puede validar el token sin necesidad de un almacén de sesiones, lo cual es adecuado para los microservicios. El problema radica en la revocación: un token permanece válido hasta que expira, por lo que siempre se debe establecer el parámetro expiresIn, algo que este fragmento omite.

OAuth 2.0

OAuth 2.0 es lo que permite el acceso delegado: “Iniciar sesión con Google”, inicio de sesión en Facebook, Microsoft Enterprise Single Sign-On, conectores CRM y cualquier aplicación de terceros que actúe en nombre del usuario. En el flujo común de código de autorización:

  1. El usuario aprueba el acceso solicitado en el proveedor.
  2. El proveedor redirige al usuario con un código de autorización de corta duración.
  3. Su servidor intercambia ese código por un token de acceso.
  4. Las llamadas a la API se realizan con el token de acceso.

Vale la pena aprender en profundidad: tokens de acceso y de actualización, el flujo de código de autorización, el flujo de credenciales del cliente para llamadas máquina a máquina, PKCE y OpenID Connect, una capa de identidad sobre OAuth.

5. Resiliencia: diseño para fallos

Las redes se caen y las dependencias dejan de funcionar. Las integraciones fiables asumen que esto ocurrirá.

Volver a intentar llamadas fallidas

Un bucle básico de reintentos:

for (let i = 0; i < 3; i++) {
  try {
    return await axios.get(url);
  } catch (error) {
    console.log("Retrying...");
  }
}

Tal como está escrito, vuelve a intentarlo de inmediato sin pausa, y si los tres intentos fallan devuelve undefined en lugar de lanzar el último error, por lo que quien llama no puede saber qué salió mal. Vuelva a lanzar el error después del intento final, y solo intente de nuevo los fallos transitorios (errores de red, tiempos de espera, códigos 5xx, 429), no los códigos 4xx que fallarán de la misma manera en cada ocasión. Tenga cuidado al volver a intentar solicitudes no idempotentes como los pagos, a menos que la API soporte claves de idempotencia.

Tiempo de espera

Una solicitud sin tiempo de espera puede quedar atascada indefinidamente y ocupar recursos mientras lo está. Siempre establezca uno:

axios.get(url, {
  timeout: 5000
});

Retraso exponencial

Volver a intentarlo a intervalos fijos sigue sobrecargando un servicio con problemas:

1s
1s
1s
1s

Doblar el tiempo de espera cada vez le da espacio para recuperarse:

1s
2s
4s
8s
16s

El cálculo se realiza en una sola línea:

const delay = attempt =>
  Math.pow(2, attempt) * 1000;

Establezca un límite máximo para el retraso y añada variaciones aleatorias para que los muchos clientes que fallan al mismo tiempo no intenten nuevamente de forma sincronizada.

Disyuntores eléctricos

Un disyuntor eléctrico cuenta las fallas en un servicio downstream y, al superar un umbral, deja de llamarlo durante un período de enfriamiento antes de enviar una solicitud de prueba. Esto evita fallos en cadena, agotamiento de recursos y interrupciones en todo el sistema. Opossum es una opción común en Node.js; Resilience4j cumple esta función en Java, y Hystrix se utiliza en sistemas más antiguos.

6. Transformación de datos: traducción entre sistemas

Rara vez dos sistemas coinciden en la estructura de los datos, por lo que una gran parte del trabajo de integración consiste en la traducción.

Mapeo de campos

Un sistema utiliza camelCase:

{
  "firstName": "John"
}

otro espera snake_case:

{
  "first_name": "John"
}

Un pequeño mapeador conecta ambos:

function transform(user) {
  return {
    first_name: user.firstName
  };
}

Las funciones de mapeo puras son fáciles de probar unitariamente y evitan que las peculiaridades de los proveedores afecten la lógica del negocio.

JSON y XML

Muchos sistemas heredados todavía utilizan XML, mientras que los servicios más recientes generan JSON; por eso una capa de integración suele convertir entre ambos en ambas direcciones.

Fechas

Un lado puede enviar el formato ISO:

2026-06-26

mientras que el otro espera la notación con el día primero:

26/06/2026

Realice conversiones explícitas y sea claro respecto a las zonas horarias cuando los valores incluyan horas; una fecha desplazada más allá de la medianoche es un error clásico en la integración.

Cantidades monetarias

Un servicio indica una cantidad decimal:

{
  "amount": 10.50
}

El otro requiere unidades fraccionarias enteras:

{
  "amount_cents": 1050
}

Los valores de punto flotante no pueden representar con exactitud cada decimal, por lo que es necesario redondear al convertir (por ejemplo Math.round(amount * 100)) y preferir centavos enteros en el interior del sistema.

Cómo se combinan los patrones en la práctica

Un diseño empresarial típico coloca una pasarela de Node.js delante de varios servidores backend:

Frontend
   |
Node.js API Gateway
   |
   +-- Authentication Service
   +-- Payment Service
   +-- CRM Service
   +-- ERP Systems
   +-- Notification Service

Estas conexiones combinan los patrones anteriores: APIs de solicitud-respuesta, JWT y OAuth, webhooks, mecanismos de reintentos y protección contra fallos, capas de transformación, además de monitoreo y registro. Para los ingenieros que se dedican al trabajo de integración, las áreas que brindan mayores beneficios primero son las APIs REST, los webhooks, JWT, OAuth 2.0, la transformación de datos y el diseño basado en eventos, seguidas por las técnicas de reintentos y resiliencia, y finalmente los mecanismos de sondeo y protección contra fallos.

Puntos clave

  • Utilice el modelo solicitud-respuesta para operaciones rápidas; cambie a polling o webhooks cuando el proceso requiera más tiempo.
  • Verifique las firmas de los webhooks, elimine duplicados en los eventos y responda rápidamente.
  • Mantenga las credenciales en la configuración, establezca una fecha de vencimiento para los tokens y aprenda adecuadamente los flujos OAuth.
  • Intente nuevamente solo ante fallos transitorios, con tiempos de espera definidos, un retroceso exponencial limitado y variabilidad en los intentos.
  • Aíslé el mapeo de datos en funciones puras probadas, y trate las fechas y el dinero con especial cuidado.

Lecturas relacionadas

  • Comprendiendo las claves de idempotencia en los endpoints POST de Node.js — Explica por qué las solicitudes POST fallan de manera impredecible al intentarse nuevamente y cómo las claves de idempotencia generadas por el cliente permiten a las APIs de Node.js manejar con seguridad las solicitudes duplicadas.
  • Previendo actualizaciones perdidas en Node.js y MongoDB bajo escrituras concurrentes — Aprenda cómo las actualizaciones condicionales atómicas, el bloqueo optimista basado en versiones, las respuestas 409 y las transacciones impiden que las escrituras concurrentes en MongoDB descarten datos silenciosamente.