CodeGym /Cursos /Módulo 5. Spring /Lección 290: Suscripciones (Subscriptions) en GraphQL

Lección 290: Suscripciones (Subscriptions) en GraphQL

Módulo 5. Spring
Nivel 15 , Lección 9
Disponible

Las suscripciones en GraphQL (del inglés Subscriptions) son un mecanismo para recibir datos del servidor en tiempo real, sin necesidad de reenviar peticiones constantemente. Si lo explicamos muy simple, las suscripciones permiten a los usuarios "conectarse" a ciertos eventos o cambios de datos para recibir notificaciones justo cuando ocurren.

Las suscripciones hacen tu aplicación más dinámica e interactiva. Imagina:

  • Aplicación de chat, que actualiza los mensajes en tiempo real sin necesidad de recargar la página.
  • Subasta online, donde los usuarios ven las nuevas pujas al instante.
  • Streaming deportivo, que actualiza el marcador del partido en directo.

Las suscripciones reemplazan mecanismos "pesados" como el polling periódico o las conexiones HTTP de larga duración.


¿Cómo funcionan las suscripciones en GraphQL?

Las suscripciones usan WebSocket para establecer una conexión persistente entre cliente y servidor. Cuando el cliente se suscribe a un evento, el servidor mantiene el canal abierto y envía las actualizaciones conforme aparecen. Es como suscribirse a un boletín: te suscribes una vez y luego recibes notificaciones.

Ejemplo de suscripción a un nuevo mensaje en un chat en GraphQL:


subscription OnNewMessage {
  newMessage(chatId: "123") {
    id
    content
    sender {
      name
    }
    timestamp
  }
}

Componentes de las suscripciones

  1. Esquema GraphQL: define los tipos de datos que se devolverán por la suscripción.
  2. Event Publisher: mecanismo para generar eventos en el servidor (Spring Boot usa Project Reactor para flujos reactivos).
  3. Transporte WebSocket: proporciona la comunicación bidireccional entre cliente y servidor.

Implementación de suscripciones en Spring GraphQL

Vamos a configurar suscripciones para tu aplicación Spring Boot con GraphQL.

1. Configurar dependencias

Para trabajar con suscripciones necesitas añadir dependencias en el pom.xml. No te olvides de añadir el transporte WebSocket de GraphQL.


<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-spring-boot-starter</artifactId>
    <version>11.1.0</version>
</dependency>
<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-java-tools</artifactId>
    <version>11.1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

Después de añadir las dependencias recuerda ejecutar el mágico comando mvn clean install para que Maven descargue lo necesario.

2. Crear el esquema de suscripción

Creamos un archivo schema.graphqls y describimos nuestra suscripción.


type Subscription {
  messageAdded: Message
}

type Message {
  id: ID
  text: String
  sender: String
  timestamp: String
}

Aquí creamos el tipo Subscription con un evento — messageAdded — que devuelve un objeto del tipo Message.

3. Crear el Event Publisher (generador de eventos)

Ahora implementamos el mecanismo de publicación de eventos. Usamos Spring Flux y los flujos reactivos de Project Reactor.

Añadimos la clase MessagePublisher:


import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.util.ArrayList;
import java.util.List;

@Component
public class MessagePublisher {

    private final List<String> messages = new ArrayList<>();
    private FluxSink<String> sink;

    public Flux<String> getPublisher() {
        return Flux.create(emitter -> this.sink = emitter);
    }

    public void addMessage(String message) {
        messages.add(message);
        if (sink != null) {
            sink.next(message); // Publicamos el nuevo mensaje
        }
    }
}

4. Implementar la suscripción en GraphQL

Ahora creamos la suscripción en Spring GraphQL. Añadimos la clase MessageSubscription.


import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;

@Controller
public class MessageSubscription {

    private final MessagePublisher messagePublisher;

    public MessageSubscription(MessagePublisher messagePublisher) {
        this.messagePublisher = messagePublisher;
    }

    @SubscriptionMapping
    public Flux<String> messageAdded() {
        return messagePublisher.getPublisher();
    }
}

El método messageAdded se suscribe al flujo de eventos, y tan pronto como se añada un nuevo mensaje en MessagePublisher, se enviará al cliente.

5. Modificar el servicio existente para publicar eventos

Actualizamos el servicio que añade mensajes para que los publique a través de nuestro MessagePublisher.


import org.springframework.stereotype.Service;

@Service
public class MessageService {

    private final MessagePublisher messagePublisher;

    public MessageService(MessagePublisher messagePublisher) {
        this.messagePublisher = messagePublisher;
    }

    public void addNewMessage(String message) {
        messagePublisher.addMessage(message);
        System.out.println("Mensaje añadido: " + message);
    }
}

Probar las suscripciones

Para probar las suscripciones usa GraphQL Playground o Altair. Ambas herramientas soportan conexiones WebSocket.

1. Arranca la aplicación.

2. Abre GraphQL Playground y ejecuta la suscripción:


subscription {
  messageAdded
}

3. En otra ventana de GraphQL ejecuta la mutación para añadir un mensaje:


mutation {
  addMessage(text: "¡Hola, GraphQL!") {
    id
    text
    timestamp
  }
}

Si todo está configurado correctamente, verás al instante en la ventana de la suscripción el nuevo mensaje. ¡Momento mágico!


Construir aplicaciones reactivas con suscripciones

Las suscripciones encajan perfectamente con el enfoque reactivo. Usando WebFlux en lugar de flujos clásicos, puedes crear aplicaciones reactivas capaces de manejar miles de suscriptores simultáneamente con un coste mínimo.

Ejemplo práctico: construir un sistema de notificaciones que envíe actualizaciones a todos los usuarios suscritos, sin importar su número.


Errores típicos y consejos

Trabajar con suscripciones tiene sus trampas comunes. Por ejemplo:

  • La conexión WebSocket no se establece. Comprueba si tienes WebSocket habilitado en la aplicación y si el transporte de GraphQL está bien configurado.
  • Los eventos llegan con retraso. Puede deberse a la ausencia de un procesamiento realmente asíncrono de los eventos.
  • Mensajes perdidos. Si el cliente se desconecta, la implementación actual de MessagePublisher pierde datos. Para sistemas críticos deberías añadir un buffer o usar un broker de mensajes (por ejemplo, Kafka).

Dominar el mecanismo de suscripciones en GraphQL te abre la puerta para crear aplicaciones altamente interactivas. ¡Éxitos en el desarrollo!

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION