Actualización y Eliminación de Productos con GraphQL

Clase 15 de 24Curso de GraphQL con Node.js

Contenido del curso

Resumen

Completar las operaciones CRUD en una API GraphQL requiere dominar las mutations de actualización y eliminación. Estas dos operaciones transforman datos en el servidor y, junto con la creación y lectura, conforman el ciclo completo de gestión de cualquier entidad. A continuación se desglosa cómo implementarlas paso a paso, desde el esquema hasta el resolver, aprovechando la capa de servicios existente.

¿Cómo se definen las mutations de update y delete en el esquema de GraphQL?

Dentro del esquema, tanto actualizar como eliminar se clasifican como mutations porque producen un cambio en la base de datos [0:38]. Para updateProduct se necesitan dos argumentos:

  • El ID del producto que se desea modificar.
  • Un input llamado UpdateProductDTO con los campos opcionales: nombre, precio, descripción, imagen y categoría.

Ninguno de estos campos es obligatorio de forma individual, pero el DTO en sí mismo sí lo es; no se puede enviar un valor nulo [1:10]. La mutation retorna un Product, aunque puede devolver nulo si el ID no existe, por eso se omite el signo de exclamación en el esquema.

Para deleteProduct la firma es más simple: recibe únicamente el ID del producto y retorna el ID del elemento eliminado [1:48].

¿Cómo funcionan los resolvers y las promesas directas en Apollo Server?

Al implementar los resolvers, Apollo Server ofrece un comportamiento muy útil: si un resolver retorna una promesa, el servidor la resuelve automáticamente sin necesidad de usar async/await [2:30]. Esto significa que, cuando no se requiere manipular el resultado antes de devolverlo, se puede retornar la promesa de forma directa y ahorrar líneas de código.

javascript // En lugar de: async updateProduct(_, { id, dto }) { const result = await service.update(id, dto); return result; }

// Se puede escribir: updateProduct(_, { id, dto }) { return service.update(id, dto); }

Sin embargo, en el caso de deleteProduct sí resulta conveniente usar await, porque tras eliminar el registro se necesita retornar el ID del producto eliminado, no la respuesta cruda del servicio [7:15].

javascript async deleteProduct(_, { id }) { await service.delete(id); return id; }

Ambos resolvers se registran dentro del objeto de mutations en el índice de resolvers [4:18].

¿Qué errores comunes aparecen al ejecutar estas mutations en el playground?

¿Cómo se ejecutan varias mutations en una sola operación?

GraphQL permite agrupar múltiples mutations en una sola operación. En el playground se define un nombre como updateAndDelete, se declaran las variables necesarias ($idUpdate, $changes, $idDelete) y se ejecutan ambas mutaciones juntas [4:45].

Al probar la actualización, el producto con ID 1 se modifica correctamente y el cambio se refleja de inmediato en consultas posteriores [6:20].

¿Por qué falla la eliminación de un producto relacionado?

Al intentar eliminar un producto, pueden surgir dos problemas:

  • Formato de retorno incorrecto. Si el servicio devuelve la promesa completa en vez del ID, GraphQL lanza un error de tipo non-null porque espera un ID válido [7:30].
  • Restricción de integridad referencial. Cuando el producto está asociado a una orden de compra, la base de datos relacional impide su eliminación [8:10]. Esto es una protección: no se puede borrar un registro que otras tablas referencian.

La solución al primer caso es resolver la promesa y retornar explícitamente el ID. Para el segundo, existen dos caminos: configurar una eliminación en cascada en la base de datos —lo cual es delicado— o aceptar la restricción como medida de seguridad y eliminar solo productos sin relaciones activas [8:40].

Al eliminar un producto sin referencias (por ejemplo, el producto 15), la operación se completa sin errores y retorna el ID eliminado junto con la actualización del producto 1, todo en una sola consulta [9:20].

¿Por qué es importante la clean architecture al agregar GraphQL?

Un punto fundamental es la reutilización de la capa de servicios. Toda la lógica de negocio —update, delete— ya existía en la arquitectura REST. Al agregar GraphQL con Apollo Server, los resolvers simplemente llaman a esos mismos servicios sin duplicar código [9:55]. Cuando las responsabilidades están bien separadas, cambiar o añadir una capa de presentación no implica reescribir la lógica central.

¿Has enfrentado problemas de integridad referencial al eliminar registros en tus proyectos? Comparte tu experiencia y cómo lo resolviste.