Saltar al contenido

Lección 11 de 20 · Lectura y práctica

Configurar Suscripciones con Apollo Server y WebSockets

Concepto claveLas suscripciones GraphQL son una característica que permite a los clientes recibir actualizaciones en tiempo real cuando ocurren cambios específicos en los datos del servidor. A diferencia de las consultas y.

Del concepto a la práctica

Taller de esta lección

Configurar una suscripción implica coordinar dos transportes: las consultas y mutaciones viajan por la ruta habitual, mientras la suscripción mantiene un canal persistente. La prueba principal no es ver una pantalla, sino demostrar que un evento publicado llega a una operación suscrita y que una conexión cerrada deja de recibirlo.

Ejemplo resuelto

Evento local ROOM_RENAMED con { roomId: "r1", name: "Norte 2" }. La suscripción solicita roomRenamed { roomId name } y recibe exactamente ese objeto cuando una mutación publica el evento.

  1. Declara el tipo Subscription y su campo de evento.

  2. Configura el servidor WebSocket en el mismo entorno autorizado.

  3. Conecta una operación suscrita y conserva su cleanup.

  4. Ejecuta la mutación publicadora y observa un único mensaje.

Error frecuente: publicar antes de que el suscriptor esté conectado. Corrección: espera que la operación de suscripción esté registrada en el servidor y después dispara la mutación; connection_ack por sí solo no demuestra ese registro.

Pruébalo

Abre dos suscriptores, publica un renombrado y cierra uno antes del segundo evento.

Comprueba tu resultado

Ambos reciben el primer evento; solo el suscriptor activo recibe el segundo y el proceso no conserva listeners del cerrado.

Transportes y payload del laboratorio

Apollo Server no incluye automáticamente suscripciones al abrir una ruta HTTP de Next.js. Para la práctica de WebSocket utiliza un servidor Node duradero separado y graphql-ws, con el protocolo graphql-transport-ws. No mezcles el paquete retirado subscriptions-transport-ws. Un esquema común incluye Query.health, Mutation.renameRoom y Subscription.roomRenamed:RoomEvent!, con RoomEvent.roomId y name. El resolver subscribe devuelve un AsyncIterator; con graphql-subscriptions actual puedes usar pubsub.asyncIterableIterator('ROOM_RENAMED'). Publica {roomRenamed: {roomId: 'r1', name: 'Norte 2'}} para que el resolver de campo encuentre el objeto correcto.

El host Node configura WebSocketServer, comparte el esquema ejecutable y llama useServer desde graphql-ws/use/ws. Conserva el dispose de servidor y el cleanup de cada operación cliente. La prueba registra que subscribe ha creado el iterador antes de publicar; cerrar la operación debe finalizarlo. Un PubSub en RAM sirve para una instancia del laboratorio, sin prometer durabilidad ni entregas entre varios procesos.

Navegador, API y base de datos conectados por solicitudes, consultas y respuestas en sentidos opuestos.
CursaloMapa de práctica
Del navegador a los datos

El navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

Concepto clave

Las suscripciones GraphQL son una característica que permite a los clientes recibir actualizaciones en tiempo real cuando ocurren cambios específicos en los datos del servidor. A diferencia de las consultas y mutaciones tradicionales que siguen un modelo request-response, las suscripciones mantienen una conexión persistente usando WebSockets.

Imagina que estás en una sala de chat: en lugar de preguntar constantemente "¿hay mensajes nuevos?" (como haría una consulta tradicional), te suscribes al canal y recibes notificaciones automáticamente cuando alguien escribe. Apollo Server implementa esto mediante el protocolo GraphQL over WebSocket, que establece un canal bidireccional entre cliente y servidor.

Cómo funciona en la práctica

Para configurar suscripciones en Apollo Server con Next.js, necesitas tres componentes principales:

  1. Un servidor WebSocket que maneje las conexiones persistentes
  2. Un PubSub (publicador-suscriptor) que gestione los eventos
  3. Resolvers de suscripción que definan qué datos enviar

Paso a paso:

// 1. Configurar Apollo Server con soporte WebSocket
import { ApolloServer } from 'apollo-server-micro';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';

const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  subscriptions: {
    path: '/api/graphql',
  },
});

// 2. Crear instancia de WebSocketServer
const wsServer = new WebSocketServer({
  server: httpServer,
  path: '/api/graphql',
});

// 3. Conectar WebSocket con Apollo
useServer({ schema }, wsServer);

Caso de estudio

Implementemos un sistema de notificaciones en tiempo real para una aplicación de gestión de proyectos. Cuando un usuario asigna una nueva tarea, todos los miembros del equipo reciben una notificación inmediata.

ComponenteImplementación
TypeDefs
type Subscription {
  taskAssigned(projectId: ID!): Task
}
PubSub
import { PubSub } from 'graphql-subscriptions';
const pubsub = new PubSub();
Resolver de mutación
assignTask: async (_, { taskId, userId }) => {
  const task = await assignTaskToUser(taskId, userId);
  pubsub.publish('TASK_ASSIGNED', { 
    taskAssigned: task,
    projectId: task.projectId 
  });
  return task;
}
Resolver de suscripción
Subscription: {
  taskAssigned: {
    subscribe: withFilter(
      () => pubsub.asyncIterator(['TASK_ASSIGNED']),
      (payload, variables) => {
        return payload.projectId === variables.projectId;
      }
    )
  }
}
El filtro (withFilter) es crucial para evitar que los usuarios reciban notificaciones de proyectos a los que no pertenecen.

Errores comunes

  • Olvidar configurar CORS para WebSockets: Los navegadores bloquean conexiones WebSocket desde dominios no autorizados. Configura CORS tanto para HTTP como para WebSocket.
  • No manejar reconexiones: Las conexiones WebSocket pueden fallar. Implementa lógica de reconexión en el cliente con backoff exponencial.
  • Filtrar mal los eventos: Sin filtros adecuados, los usuarios reciben datos que no les corresponden, comprometiendo seguridad y rendimiento.
  • Ignorar el escalado horizontal: PubSub en memoria no funciona con múltiples instancias del servidor. Para producción, usa Redis PubSub.
  • No limpiar suscripciones: En React/Next.js, debes limpiar las suscripciones en useEffect para evitar memory leaks.

Checklist de dominio

  1. ¿Puedes configurar Apollo Server con soporte WebSocket en Next.js?
  2. ¿Sabes implementar un resolver de suscripción con filtros?
  3. ¿Entiendes la diferencia entre pubsub.publish() y pubsub.asyncIterator()?
  4. ¿Puedes conectar un cliente Apollo a suscripciones desde React?
  5. ¿Sabes manejar errores de conexión WebSocket?
  6. ¿Puedes escalar suscripciones usando Redis en producción?
  7. ¿Entiendes cuándo usar suscripciones vs polling vs Server-Sent Events?

Implementar un chat en tiempo real con GraphQL Subscriptions

Crea un sistema de chat básico donde los usuarios puedan enviar mensajes y ver los mensajes de otros en tiempo real.

  1. Configura Apollo Server en Next.js con soporte para WebSockets
  2. Define los tipos GraphQL necesarios:
    • Mensaje: id, contenido, usuario, timestamp
    • Mutation: enviarMensaje(contenido: String!, usuario: String!): Mensaje
    • Subscription: mensajeEnviado: Mensaje
  3. Implementa el resolver para la mutación enviarMensaje que publique el evento
  4. Implementa el resolver para la suscripción mensajeEnviado
  5. Crea un componente React que:
    • Muestre los mensajes existentes
    • Permita enviar nuevos mensajes
    • Se suscriba para recibir mensajes nuevos en tiempo real
  6. Prueba abriendo dos pestañas del navegador y enviando mensajes desde ambas
Pistas
  • Usa graphql-ws para el servidor WebSocket
  • Recuerda limpiar la suscripción en el cleanup de useEffect
  • El timestamp puede generarse con new Date().toISOString()

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con GraphQL Profesional con Next.js y Apollo Server: APIs Tipadas y Suscripciones

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.