Introducción
Las suscripciones en GraphQL permiten a los clientes recibir actualizaciones en tiempo real desde el servidor. Esto es especialmente útil para aplicaciones que requieren datos en tiempo real, como chats, notificaciones, o cualquier tipo de actualización en vivo.
Conceptos Clave
- Suscripción: Una operación de GraphQL que permite a los clientes escuchar eventos específicos en el servidor.
- Publicación/Suscripción (Pub/Sub): Un patrón de mensajería donde los emisores (publicadores) envían mensajes a un canal y los receptores (suscriptores) reciben esos mensajes.
- WebSocket: Un protocolo de comunicación que permite la interacción bidireccional entre el cliente y el servidor.
Configuración de Suscripciones en GraphQL
Paso 1: Configuración del Servidor
Para configurar suscripciones en un servidor GraphQL, generalmente se utiliza una biblioteca como Apollo Server
. A continuación, se muestra cómo configurar un servidor con suscripciones:
const { ApolloServer, gql, PubSub } = require('apollo-server'); const pubsub = new PubSub(); const typeDefs = gql` type Message { id: ID! content: String! } type Query { messages: [Message!] } type Mutation { postMessage(content: String!): ID! } type Subscription { messagePosted: Message! } `; const messages = []; let id = 0; const resolvers = { Query: { messages: () => messages, }, Mutation: { postMessage: (parent, { content }) => { const message = { id: id++, content }; messages.push(message); pubsub.publish('MESSAGE_POSTED', { messagePosted: message }); return message.id; }, }, Subscription: { messagePosted: { subscribe: () => pubsub.asyncIterator(['MESSAGE_POSTED']), }, }, }; const server = new ApolloServer({ typeDefs, resolvers, subscriptions: { path: '/subscriptions', }, }); server.listen().then(({ url, subscriptionsUrl }) => { console.log(`Server ready at ${url}`); console.log(`Subscriptions ready at ${subscriptionsUrl}`); });
Explicación del Código
-
Definición del Esquema:
typeDefs
define los tiposMessage
,Query
,Mutation
ySubscription
.Subscription
define un campomessagePosted
que emite eventos de tipoMessage
.
-
Publicador/Suscriptor:
PubSub
es una implementación simple de pub/sub en memoria.pubsub.publish('MESSAGE_POSTED', { messagePosted: message })
publica un evento cuando se crea un nuevo mensaje.
-
Resolvers:
postMessage
enMutation
crea un nuevo mensaje y lo publica.messagePosted
enSubscription
se suscribe a los eventosMESSAGE_POSTED
.
-
Servidor Apollo:
subscriptions: { path: '/subscriptions' }
habilita las suscripciones en la ruta especificada.
Paso 2: Configuración del Cliente
Para suscribirse a eventos desde el cliente, se puede usar Apollo Client
con WebSocket. A continuación, se muestra un ejemplo de configuración del cliente:
import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client'; import { WebSocketLink } from '@apollo/client/link/ws'; import { getMainDefinition } from '@apollo/client/utilities'; const httpLink = new HttpLink({ uri: 'http://localhost:4000/', }); const wsLink = new WebSocketLink({ uri: `ws://localhost:4000/subscriptions`, options: { reconnect: true, }, }); const splitLink = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, httpLink, ); const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(), }); export default client;
Explicación del Código
-
Enlaces HTTP y WebSocket:
HttpLink
se utiliza para consultas y mutaciones.WebSocketLink
se utiliza para suscripciones.
-
División de Enlaces:
split
se utiliza para enrutar las operaciones a través del enlace adecuado (HTTP o WebSocket) según el tipo de operación.
Ejemplo de Suscripción en el Cliente
import { gql, useSubscription } from '@apollo/client'; const MESSAGE_POSTED = gql` subscription OnMessagePosted { messagePosted { id content } } `; function Messages() { const { data, loading } = useSubscription(MESSAGE_POSTED); if (loading) return <p>Loading...</p>; return ( <div> <h2>Messages</h2> {data.messagePosted.map((message) => ( <p key={message.id}>{message.content}</p> ))} </div> ); } export default Messages;
Explicación del Código
-
Definición de la Suscripción:
MESSAGE_POSTED
es una suscripción que escucha eventosmessagePosted
.
-
Uso de la Suscripción:
useSubscription
se utiliza para suscribirse aMESSAGE_POSTED
y actualizar la UI en tiempo real.
Ejercicio Práctico
Ejercicio
-
Configura un servidor GraphQL con suscripciones:
- Define un tipo
Comment
con camposid
ycontent
. - Crea una mutación
postComment
que publique un eventocommentPosted
. - Define una suscripción
commentPosted
que emita eventos de tipoComment
.
- Define un tipo
-
Configura un cliente que se suscriba a
commentPosted
:- Usa
Apollo Client
para configurar los enlaces HTTP y WebSocket. - Crea un componente que muestre los comentarios en tiempo real.
- Usa
Solución
Servidor
const { ApolloServer, gql, PubSub } = require('apollo-server'); const pubsub = new PubSub(); const typeDefs = gql` type Comment { id: ID! content: String! } type Query { comments: [Comment!] } type Mutation { postComment(content: String!): ID! } type Subscription { commentPosted: Comment! } `; const comments = []; let id = 0; const resolvers = { Query: { comments: () => comments, }, Mutation: { postComment: (parent, { content }) => { const comment = { id: id++, content }; comments.push(comment); pubsub.publish('COMMENT_POSTED', { commentPosted: comment }); return comment.id; }, }, Subscription: { commentPosted: { subscribe: () => pubsub.asyncIterator(['COMMENT_POSTED']), }, }, }; const server = new ApolloServer({ typeDefs, resolvers, subscriptions: { path: '/subscriptions', }, }); server.listen().then(({ url, subscriptionsUrl }) => { console.log(`Server ready at ${url}`); console.log(`Subscriptions ready at ${subscriptionsUrl}`); });
Cliente
import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client'; import { WebSocketLink } from '@apollo/client/link/ws'; import { getMainDefinition } from '@apollo/client/utilities'; import { gql, useSubscription } from '@apollo/client'; const httpLink = new HttpLink({ uri: 'http://localhost:4000/', }); const wsLink = new WebSocketLink({ uri: `ws://localhost:4000/subscriptions`, options: { reconnect: true, }, }); const splitLink = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, httpLink, ); const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(), }); const COMMENT_POSTED = gql` subscription OnCommentPosted { commentPosted { id content } } `; function Comments() { const { data, loading } = useSubscription(COMMENT_POSTED); if (loading) return <p>Loading...</p>; return ( <div> <h2>Comments</h2> {data.commentPosted.map((comment) => ( <p key={comment.id}>{comment.content}</p> ))} </div> ); } export default Comments;
Conclusión
Las suscripciones de GraphQL son una poderosa herramienta para aplicaciones que requieren actualizaciones en tiempo real. Al comprender cómo configurar y utilizar suscripciones, puedes mejorar significativamente la interactividad y la experiencia del usuario en tus aplicaciones. En el siguiente módulo, exploraremos más herramientas y el ecosistema de GraphQL para seguir ampliando tus habilidades.
Curso de GraphQL
Módulo 1: Introducción a GraphQL
- ¿Qué es GraphQL?
- GraphQL vs REST
- Configuración de un Servidor GraphQL
- Conceptos Básicos del Esquema de GraphQL
Módulo 2: Conceptos Fundamentales
Módulo 3: Diseño Avanzado de Esquemas
Módulo 4: Trabajando con Datos
Módulo 5: Rendimiento y Seguridad
Módulo 6: Herramientas y Ecosistema
Módulo 7: Pruebas y Despliegue
- Pruebas Unitarias de Resolvers
- Pruebas de Integración
- Integración Continua
- Despliegue de Servidores GraphQL