Saltar al contenido

Lección 18 de 20 · Lectura y práctica

Desarrollar Funcionalidades de Publicaciones y Comentarios

Concepto claveEn 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.

Del concepto a la práctica

Taller de esta lección

Publicaciones y comentarios forman una relación uno-a-muchos con reglas diferentes: crear un comentario exige una publicación existente y un autor autorizado, mientras consultar comentarios debe conservar su relación y orden. El texto se valida antes de emitir cualquier evento.

Ejemplo resuelto

Post p1 pertenece a u1. Comentario c1 de u2 contiene "Buen análisis"; post(id:"p1").comments devuelve [c1]. Un comentario con postId:"p9" se rechaza porque la publicación no existe.

  1. Define Post.comments: [Comment!]! y Comment.post: Post!.

  2. Comprueba que el cuerpo no esté vacío tras recortarlo.

  3. Busca la publicación y verifica que sea visible para el autor.

  4. Guarda el comentario y resuelve la relación por identificador.

Error frecuente: aceptar postId válido sin comprobar permisos de visibilidad. Corrección: aplica la misma regla de acceso en la operación de creación.

Pruébalo

Crea un comentario válido para p1, otro para p9 y consulta los comentarios de p1.

Comprueba tu resultado

Solo c1 existe, p1.comments contiene un elemento y la creación contra p9 falla antes de modificar datos.

IDs y autor pertenecen al servidor

Fija inicialmente p1 visible, u2 autorizado y ningún comentario. La mutación recibe postId y body; el servicio asigna c1 y obtiene authorId de la sesión. La transacción guarda ambos vínculos y solo entonces genera el evento. Leer comments o navegar Comment.post aplica la política de acceso correspondiente; esconder p1 del feed no protege una consulta directa por ID. Para p9 no hay escritura ni evento. El cuerpo se trata como texto y la interfaz lo escapa; no lo renderices como HTML confiable.

Navegador, API y base de datos conectados por solicitudes, consultas y respuestas en sentidos opuestos.
CursaloMapa de práctica
Del navegador a los datos

El navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

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.

Sigue con GraphQL Profesional con Next.js y Apollo Server: APIs Tipadas y Suscripciones

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.