Concepto clave
En una API GraphQL para una red social, las publicaciones y comentarios forman el núcleo de la interacción entre usuarios. Piensa en esto como una conversación en una cafetería: las publicaciones son los temas principales que alguien inicia ("¿Qué piensan sobre las nuevas tecnologías?"), y los comentarios son las respuestas de los demás ("Me encanta cómo facilitan el trabajo"). En GraphQL, modelamos esto con tipos tipados que definen la estructura de los datos y resolvers que manejan la lógica de negocio, como crear, leer, actualizar o eliminar contenido.
La relación entre publicaciones y comentarios es jerárquica: una publicación puede tener muchos comentarios, pero cada comentario pertenece a una sola publicación. Esto se implementa en GraphQL mediante tipos anidados y resolvers anidados, donde el resolver de comentarios accede al contexto de la publicación padre. Por ejemplo, al consultar una publicación, GraphQL puede incluir automáticamente sus comentarios relacionados, gracias a resolvers que "resuelven" estos campos en tiempo de ejecución.
Cómo funciona en la práctica
Vamos a construir esto paso a paso en nuestro proyecto con Next.js y Apollo Server. Primero, definimos los tipos GraphQL en un esquema tipado usando TypeScript o GraphQL SDL. Luego, implementamos los resolvers para manejar las operaciones CRUD. Aquí un ejemplo básico:
// types.graphql
type Post {
id: ID!
content: String!
author: User!
comments: [Comment!]!
createdAt: String!
}
type Comment {
id: ID!
content: String!
author: User!
post: Post!
createdAt: String!
}
input CreatePostInput {
content: String!
authorId: ID!
}
input CreateCommentInput {
content: String!
authorId: ID!
postId: ID!
}En los resolvers, usamos Apollo Server para conectar con una base de datos (como PostgreSQL o MongoDB). Por ejemplo, el resolver para crear una publicación:
// resolvers/postResolvers.ts
const postResolvers = {
Mutation: {
createPost: async (_, { input }: { input: CreatePostInput }, context) => {
// Validar entrada y autorización
const post = await db.post.create({
data: {
content: input.content,
authorId: input.authorId,
},
});
return post;
},
},
Post: {
comments: async (parent) => {
// Resolver anidado para cargar comentarios de esta publicación
return await db.comment.findMany({ where: { postId: parent.id } });
},
},
};Para las suscripciones, podemos usar Apollo Server con PubSub para notificar en tiempo real cuando se agrega un nuevo comentario a una publicación, permitiendo funcionalidades como feeds en vivo.
Caso de estudio
Imagina que estamos desarrollando una red social llamada "SocialGraph". Un usuario, Ana, publica: "Acabo de terminar mi proyecto con GraphQL y Next.js". En nuestra API, esto dispara una mutación createPost que:
- Valida que Ana esté autenticada (usando el contexto de Apollo Server).
- Inserta la publicación en la base de datos con su contenido y ID de autor.
- Devuelve el objeto Post con campos como ID, contenido y fecha de creación.
Luego, otro usuario, Carlos, comenta: "¡Felicidades, Ana! ¿Podrías compartir el código?". Esto usa la mutación createComment:
| Paso | Acción | Resultado en GraphQL |
|---|---|---|
| 1 | Carlos envía input con contenido, su authorId, y postId de la publicación de Ana | Mutation createComment |
| 2 | Resolver valida que el postId exista y Carlos tenga permiso | Retorna error o procede |
| 3 | Se inserta el comentario en la base de datos | Nuevo objeto Comment creado |
| 4 | Si hay suscripciones activas, se notifica a los suscriptores | Subscription newComment |
En una red social real, este flujo debe incluir paginación para comentarios (ej., cargar los primeros 10) y optimizaciones como DataLoader para evitar problemas N+1 en consultas.
Errores comunes
- No validar permisos en resolvers: Olvidar verificar que un usuario solo pueda comentar en publicaciones visibles o editar sus propios comentarios. Solución: Usar el contexto de Apollo Server para incluir información de autenticación y añadir checks en cada resolver.
- Consultas N+1 en resolvers anidados: Si el resolver de
Post.commentshace una consulta a la base de datos por cada publicación, puede ralentizar la API. Solución: Implementar DataLoader para agrupar y cachear consultas, o usar joins en la consulta principal. - Tipos GraphQL mal definidos: Por ejemplo, definir
comments: [Comment]sin!puede permitir valores null que rompan la aplicación cliente. Solución: Usar tipos no nulos (!) donde sea apropiado y probar con herramientas como GraphQL Code Generator. - Ignorar errores de entrada: No sanitizar o validar el contenido de publicaciones y comentarios, lo que puede llevar a inyecciones o datos corruptos. Solución: Usar bibliotecas como Zod o class-validator en los inputs.
- No manejar suscripciones de forma eficiente: Suscribirse a todos los comentarios sin filtros puede saturar el servidor. Solución: Usar argumentos en suscripciones, como
newComment(postId: ID!), para limitar las notificaciones.
Checklist de dominio
- ¿Puedes definir tipos GraphQL para Post y Comment con relaciones correctas usando SDL o TypeScript?
- ¿Implementas resolvers para mutaciones como createPost y createComment con validación y autorización?
- ¿Usas resolvers anidados para cargar comentarios de una publicación, optimizados con DataLoader?
- ¿Configuras suscripciones en Apollo Server para notificar nuevos comentarios en tiempo real?
- ¿Manejas errores y paginación en consultas de publicaciones y comentarios?
- ¿Integras esta API con un cliente Next.js usando Apollo Client para mostrar datos?
- ¿Pruebas los resolvers con herramientas como Jest o GraphQL Playground?
Implementar CRUD de Publicaciones y Comentarios con Suscripciones
En este ejercicio, extenderás el proyecto de red social para añadir funcionalidades completas de publicaciones y comentarios. Sigue estos pasos:
- Define los tipos GraphQL: En tu archivo de esquema (ej.,
schema.graphql), añade los tipos Post y Comment con campos como id, content, author, createdAt, y relaciones. Incluye inputs para crear y actualizar. - Crea los resolvers: En una carpeta
resolvers, implementa resolvers para las queries (ej.,posts,post(id)), mutations (ej.,createPost,createComment,deleteComment), y el resolver anidadoPost.comments. Usa una base de datos simulada o real (ej., un array en memoria o Prisma con SQLite). - Añade suscripciones: Configura Apollo Server para soportar suscripciones usando PubSub. Crea una suscripción
newCommentque notifique cuando se agregue un comentario a una publicación específica, pasando el postId como argumento. - Integra con Next.js: En el lado cliente (páginas de Next.js), usa Apollo Client para realizar una mutación que cree una publicación y luego suscríbete a nuevos comentarios para mostrarlos en tiempo real.
- Prueba la funcionalidad: Usa GraphQL Playground o una herramienta similar para probar las queries, mutations y suscripciones. Verifica que los datos persistan y las notificaciones funcionen.
Entrega: Un repositorio Git con el código completo, incluyendo esquemas, resolvers, configuración de Apollo Server, y un ejemplo de uso en Next.js.
Pistas- Usa context en Apollo Server para pasar información de autenticación a los resolvers, aunque en este ejercicio puedas simularlo con IDs fijos.
- Para suscripciones, recuerda publicar eventos en el resolver de createComment usando PubSub.publish().
- Si usas TypeScript, genera tipos automáticamente a partir del esquema GraphQL con GraphQL Code Generator para evitar errores.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.