Desarrollar Funcionalidades de Publicaciones y Comentarios

Lectura
20 min~6 min lectura

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:

  1. Valida que Ana esté autenticada (usando el contexto de Apollo Server).
  2. Inserta la publicación en la base de datos con su contenido y ID de autor.
  3. 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:

PasoAcciónResultado en GraphQL
1Carlos envía input con contenido, su authorId, y postId de la publicación de AnaMutation createComment
2Resolver valida que el postId exista y Carlos tenga permisoRetorna error o procede
3Se inserta el comentario en la base de datosNuevo objeto Comment creado
4Si hay suscripciones activas, se notifica a los suscriptoresSubscription 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.comments hace 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

  1. ¿Puedes definir tipos GraphQL para Post y Comment con relaciones correctas usando SDL o TypeScript?
  2. ¿Implementas resolvers para mutaciones como createPost y createComment con validación y autorización?
  3. ¿Usas resolvers anidados para cargar comentarios de una publicación, optimizados con DataLoader?
  4. ¿Configuras suscripciones en Apollo Server para notificar nuevos comentarios en tiempo real?
  5. ¿Manejas errores y paginación en consultas de publicaciones y comentarios?
  6. ¿Integras esta API con un cliente Next.js usando Apollo Client para mostrar datos?
  7. ¿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:

  1. 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.
  2. Crea los resolvers: En una carpeta resolvers, implementa resolvers para las queries (ej., posts, post(id)), mutations (ej., createPost, createComment, deleteComment), y el resolver anidado Post.comments. Usa una base de datos simulada o real (ej., un array en memoria o Prisma con SQLite).
  3. Añade suscripciones: Configura Apollo Server para soportar suscripciones usando PubSub. Crea una suscripción newComment que notifique cuando se agregue un comentario a una publicación específica, pasando el postId como argumento.
  4. 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.
  5. 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.