Concepto clave
Las suscripciones en GraphQL permiten que los clientes reciban actualizaciones en tiempo real cuando ocurren cambios en los datos del servidor. A diferencia de las queries y mutations que siguen un modelo request-response tradicional, las suscripciones mantienen una conexión persistente usando WebSockets o Server-Sent Events.
Imagina un sistema de notificaciones como el de una red social: cuando alguien comenta en tu publicación, no necesitas refrescar la página constantemente. El servidor empuja esa información a tu cliente automáticamente. GraphQL suscripciones funcionan de manera similar, donde defines eventos específicos (como "nuevoMensaje" o "usuarioConectado") y los clientes pueden suscribirse para recibir esos eventos en tiempo real.
En el contexto de Apollo Server con Next.js, implementamos suscripciones usando PubSub (Publicador-Suscriptor), un patrón donde los resolvers publican eventos y los clientes suscritos los reciben. Esto es crucial para aplicaciones que requieren actualizaciones inmediatas como chats, dashboards en vivo, o sistemas de notificaciones.
Cómo funciona en la práctica
Vamos a implementar una suscripción básica para notificaciones en tiempo real paso a paso:
- Configurar WebSocket en Apollo Server: Primero, necesitamos habilitar WebSockets en nuestro servidor Apollo. En Next.js, esto se hace en el archivo de configuración del servidor API.
- Definir el tipo de suscripción en el schema: Agregamos un tipo Subscription a nuestro schema GraphQL. Por ejemplo:
type Subscription { nuevaNotificacion: Notificacion } - Implementar el resolver de suscripción: Creamos un resolver que use PubSub para escuchar eventos. Apollo Server proporciona una implementación básica de PubSub, pero en producción se recomienda usar RedisPubSub para escalabilidad.
- Publicar eventos desde mutations: Cuando ocurre una acción relevante (como crear una notificación), publicamos un evento en el PubSub que activará la suscripción.
- Conectar el cliente Apollo: En el frontend, configuramos Apollo Client para usar WebSockets y suscribirnos a la suscripción definida.
Ejemplo de código básico para el resolver de suscripción:
const { PubSub } = require('apollo-server');
const pubsub = new PubSub();
const resolvers = {
Subscription: {
nuevaNotificacion: {
subscribe: () => pubsub.asyncIterator(['NUEVA_NOTIFICACION'])
}
},
Mutation: {
crearNotificacion: (parent, args, context) => {
const notificacion = crearNotificacionEnDB(args);
pubsub.publish('NUEVA_NOTIFICACION', { nuevaNotificacion: notificacion });
return notificacion;
}
}
};Caso de estudio
Implementemos un sistema de notificaciones para una aplicación de gestión de proyectos. Los usuarios necesitan recibir notificaciones en tiempo real cuando:
- Se les asigna una nueva tarea
- Un colega comenta en una tarea que están siguiendo
- Se acerca la fecha límite de una tarea
Schema GraphQL para este caso:
type Notificacion {
id: ID!
mensaje: String!
tipo: TipoNotificacion!
fecha: String!
leida: Boolean!
}
enum TipoNotificacion {
ASIGNACION_TAREA
COMENTARIO
RECORDATORIO
}
type Subscription {
notificacionRecibida(usuarioId: ID!): Notificacion
}Tabla de eventos y sus publicadores:
| Evento | Publicado desde | Datos incluidos |
|---|---|---|
| ASIGNACION_TAREA | Mutation asignarTarea | tareaId, usuarioAsignado, fechaLimite |
| COMENTARIO | Mutation agregarComentario | comentarioId, tareaId, autorId |
| RECORDATORIO | Job programado (cron) | tareaId, diasRestantes |
En producción, considera usar filtros en las suscripciones para que los usuarios solo reciban notificaciones relevantes. Por ejemplo: notificacionRecibida(usuarioId: "123") asegura que solo el usuario con ID 123 reciba sus notificaciones.Errores comunes
- No manejar desconexiones de WebSocket: Los clientes pueden desconectarse inesperadamente. Implementa lógica de reconexión en el cliente y limpia suscripciones antiguas en el servidor.
- Usar PubSub en memoria en producción: La implementación por defecto de PubSub en Apollo Server no escala. Para múltiples instancias de servidor, usa RedisPubSub o similar.
- Olvidar autorización en suscripciones: Las suscripciones deben validar permisos igual que las queries. No asumas que el cliente solo solicitará datos a los que tiene acceso.
- Sobrecargar el cliente con demasiadas actualizaciones: Diseña eventos granulares. En lugar de una suscripción "cambiosEnProyecto", crea suscripciones específicas como "tareaAgregada", "tareaCompletada", etc.
- No probar escenarios de concurrencia: Cuando muchos usuarios se suscriben simultáneamente, el servidor puede saturarse. Realiza pruebas de carga específicas para suscripciones.
Checklist de dominio
- Puedo explicar la diferencia entre queries, mutations y suscripciones en GraphQL
- He configurado WebSockets en Apollo Server con Next.js correctamente
- Implementé al menos una suscripción con filtros de argumentos
- Integré suscripciones con mutations para publicar eventos
- Probé las suscripciones desde el cliente Apollo con reconexión automática
- Optimicé el rendimiento usando PubSub externo (Redis) para entornos de producción
- Implementé autorización en resolvers de suscripción
Implementa un sistema de notificaciones en tiempo real para un chat
En este ejercicio, crearás un sistema básico de chat con notificaciones en tiempo real usando GraphQL suscripciones. Sigue estos pasos:
- Crea un nuevo proyecto Next.js con Apollo Server configurado para soportar suscripciones via WebSocket.
- Define el schema GraphQL que incluya:
- Un tipo Mensaje con id, contenido, autor y timestamp
- Una mutation enviarMensaje que publique un evento
- Una suscripcion nuevoMensaje que escuche ese evento
- Implementa los resolvers correspondientes:
- En la mutation enviarMensaje, guarda el mensaje en memoria (o una DB simple) y publica un evento con pubsub.publish
- En la suscripcion nuevoMensaje, implementa el subscribe usando pubsub.asyncIterator
- Crea un componente React que:
- Use useSubscription de Apollo Client para suscribirse a nuevoMensaje
- Muestre los mensajes en tiempo real en una lista
- Tenga un formulario para enviar nuevos mensajes via mutation
- Prueba la funcionalidad abriendo dos ventanas del navegador y verificando que los mensajes aparezcan en ambas en tiempo real.
- Usa el paquete 'subscriptions-transport-ws' para configurar WebSockets en Apollo Server
- Recuerda que las suscripciones en GraphQL devuelven un AsyncIterator, no un valor directo
- En el cliente, configura Apollo Client con WebSocketLink junto al HttpLink
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.