REST API, WebSockets y Server-Sent Events: cómo se comunican las aplicaciones web (y cuándo usar cada uno)

Ya sea que estás empezando en código o estás usando algún agente de IA para generar tu aplicación, entender cómo se comunican las aplicaciones web con el servidor te va a servir para dos cosas: ganar rendimiento y elegir el método correcto para que ciertas funcionalidades no fallen en producción.

En este artículo vamos a ver tres arquitecturas de comunicación cliente-servidor que te vas a encontrar constantemente: REST API, WebSockets y Server-Sent Events (SSE). La regla rápida sería algo así:

Pero para saber por qué, primero hay que entender la base.

La arquitectura cliente-servidor

No importa qué sitio estés usando —YouTube, Facebook, LinkedIn o cualquier web de internet—, lo primero que pasa cuando entras es esto:

  1. El navegador solicita una página a través de una dirección (por ejemplo www.algo.com). Esta solicitud tiene un nombre específico: petición o request.
  2. El servidor recibe la petición y la procesa. Dependiendo de lo que hayas solicitado, puede buscar algo en una base de datos, un archivo, una imagen... básicamente intenta resolver lo que pediste.
  3. El servidor retorna el resultado. A eso se le conoce como respuesta o response.

Esto es lo que hacen todas las webs y se conoce como arquitectura cliente-servidor: hay un servidor y pueden existir múltiples clientes, pero todos consumen desde ese mismo servidor. Así funciona prácticamente el 90% del internet de estos días.

Dos detalles importantes de este flujo:

REST API: la forma más común

Una REST API, en la práctica, es una aplicación de servidor: un programa que recibe las peticiones del cliente y les responde. Antes desarrollar una tomaba bastante trabajo; hoy con agentes de IA puedes crear una en cuestión de minutos. Pero más importante que crearla es entender cómo funciona.

Para probarlo, generé con un agente una aplicación de ejemplo: un tablero kanban de tareas (esas columnas donde mueves tarjetas de un lado a otro, tipo Trello o Notion), con frontend en React + Vite, backend en Express y SQLite como base de datos. Ni siquiera hace falta pedirle explícitamente que use HTTP o que cree una REST API: con decirle "frontend y backend", el agente entiende que necesita comunicarlos de algún modo, y esta es la forma por defecto.

Si le añadimos logs al backend para ver las peticiones que van llegando, el patrón aparece de inmediato:

Eso es una REST API funcionando: el backend va respondiendo, actualizando, eliminando y creando según lo que el cliente pida.

El problema: nadie más se entera

Aquí viene el detalle. Cuando yo cambio un dato, solo interactúan mi cliente y el servidor. Si otra persona está trabajando en el mismo tablero desde su propia interfaz y crea una "tarea 10", ella verá la respuesta del servidor en su pantalla... pero los demás no se enteran hasta que refresquen la página.

A la capacidad de que todos los clientes vean los cambios sin refrescar se le llama tiempo real (real time). Y para lograrlo existen varias estrategias.

Long polling: la forma antigua (que aún funciona)

Una técnica clásica es que el cliente consulte continuamente al servidor por si algo cambió. Gmail es el ejemplo típico: cuando surgió, la estrategia era que la aplicación del usuario preguntara cada cierto tiempo "¿tengo correos nuevos?", una y otra vez, cada ciertos segundos, sin parar.

Esto se llama long polling y funciona, pero tiene problemas evidentes:

Lo implementé en el tablero kanban pidiéndole al agente: "Implementa long polling en el frontend para estar al tanto de actualizaciones de datos". El resultado: el navegador pedía automáticamente a la API cada ~25 segundos si había cambios. Los cambios de un cliente sí terminaban apareciendo en el otro, pero con ese retraso y ese costo de peticiones constantes.

Para una aplicación de una sola persona no notas la diferencia. El problema aparece cuando trabajan múltiples personas al mismo tiempo. Y para eso, los navegadores y servidores modernos ya tienen algo mejor.

WebSockets: comunicación bidireccional

Los WebSockets rompen la regla de que el cliente siempre inicia. Aquí el cliente se conecta al servidor, el servidor se conecta con el cliente, y a partir de allí mantienen una comunicación bidireccional: el cliente puede pedir y el servidor responder, pero también el servidor puede notificar al cliente sin que este haya pedido nada.

Volviendo al ejemplo de Gmail: si un cliente envía un correo al servidor, los demás clientes —al mantener una conexión WebSocket— ven reflejado el correo nuevo en su interfaz inmediatamente. No necesitan preguntar constantemente; el servidor les avisa.

En el tablero kanban bastó con pedirle al agente: "Cambia el long polling por WebSockets". El agente creó una ruta sobre el protocolo ws:// (el protocolo de WebSockets) y la sincronización pasó a ser instantánea: no importa cuántos clientes estén conectados, cualquiera que haga una modificación la ve reflejada en todas las demás ventanas al momento.

Para probarlo de verdad, usé un skill de Playwright CLI para lanzar cuatro instancias de navegador simultáneas: dos creando tareas y dos moviendo tarjetas entre columnas. Cada acción en una ventana se reflejaba de inmediato en las otras tres. Eso es el WebSocket haciendo su trabajo.

Server-Sent Events (SSE): cuando solo necesitas que el servidor te avise

Ahora, hay casos donde la comunicación bidireccional sobra. Piensa en una interfaz sencilla de notificaciones: alguien te asignó una tarea y solo necesitas enterarte. No tienes que responder nada al servidor ni reenviar nada para que notifique al resto.

Para eso existen los Server-Sent Events (SSE): un canal donde el servidor "empuja" (push) mensajes al cliente, y el cliente solo los recibe. Es como la mitad de un WebSocket: el WebSocket puede enviar de vuelta, pero aquí no hace falta.

Casos típicos de uso:

De hecho, los SSE resuelven la mayoría de operaciones comunes sin necesidad de comunicación bidireccional. Si lo piensas, lo que casi siempre se necesita es enviar eventos desde el servidor. Así que SSE + REST API cubre prácticamente toda la comunicación bidireccional que puedas necesitar, y por eso es incluso más común que los WebSockets.

En la demo lo combiné con todo lo anterior: "Crea un feed de actividad en vivo por Server-Sent Events (solo de servidor a cliente) mientras el WebSocket sigue sincronizando el tablero". El resultado: una tarjeta de actividad que registra en tiempo real cada cambio del tablero —quién creó, movió o eliminó qué— sin que el cliente tenga que hacer nada de vuelta.

Lo importante: no son excluyentes

Si revisas los archivos del servidor de la demo, verás las tres arquitecturas conviviendo en el mismo backend:

No porque uses REST API tienes que renunciar a WebSockets, ni porque uses WebSockets dejas de poder usar SSE. Todo puede funcionar dentro del mismo servidor; cada uno sirve para características distintas.

Bonus: GraphQL, otra forma de responder

Con las tres anteriores cubres la gran mayoría de proyectos. Pero a modo de información, existe otra forma de organizar la comunicación cuyo objetivo no es el tiempo real, sino la forma en la que el servidor responde: GraphQL.

El contexto es este: cuando un servidor responde, lo hace en un formato llamado JSON, una forma de organizar datos en pares clave-valor:

{
  "name": "John",
  "age": 30
}

En la práctica, los objetos reales traen muchos más campos. Y si envías toda esa información a un dispositivo móvil que solo necesita dos o tres datos, estás desperdiciando ancho de banda y haciéndole procesar información que no va a usar.

Ahí entra GraphQL: permite que el cliente pida exactamente los datos que necesita y nada más. En la demo lo implementé como una API adicional a la REST API, y desde su interfaz de consultas puedes pedir, por ejemplo, solo los id y title de las tareas —con autocompletado incluido— y recibir únicamente eso.

Por debajo GraphQL también usa HTTP y permite las mismas operaciones (crear, listar, incluso conexiones en tiempo real), pero está pensado más como el siguiente paso una vez que ya dominas una REST API típica.

Conclusión

Implementar comunicación en tiempo real hoy es bastante sencillo, sobre todo con agentes de IA. Y estas tres formas son las que más vas a usar, tanto si estás empezando en desarrollo como si haces vibe coding:

Necesitas... Usa...
Crear, listar, actualizar, eliminar datos REST API
Chat o sincronización bidireccional en tiempo real WebSockets
Notificaciones, feeds, streaming del servidor al cliente Server-Sent Events

Si conoces estas tres, puedes desarrollar casi cualquier aplicación y saber exactamente qué pedirle a tu agente según la funcionalidad que necesites. Y cuando las domines —y tu proyecto crezca— ya puedes explorar alternativas como GraphQL, gRPC o webhooks.