Integrar GraphQL con una base de datos real es más sencillo de lo que parece cuando ya cuentas con una arquitectura bien definida por capas. La clave está en reutilizar la capa de servicios que conecta con la base de datos, exactamente la misma que ya funciona con los endpoints REST, y simplemente vincularla desde los resolvers de GraphQL.
¿Cómo se conectan los resolvers de GraphQL a la capa de servicios?
El patrón arquitectónico que se sigue consiste en mantener la lógica de negocio centralizada en la capa de servicios. Esta capa es la que realiza las consultas a la base de datos mediante un ORM como Sequelize, y tanto las rutas REST como los resolvers de GraphQL consumen esos mismos servicios.
Dentro del archivo de product resolvers se crea una instancia del servicio de productos [01:07]. A partir de ahí, cada resolver invoca los métodos correspondientes:
- Para obtener un solo producto, se utiliza
service.findOne(id), donde el id llega como argumento de la query de GraphQL [01:33].
- Para obtener la lista completa de productos, se llama a
service.find({}) sin parámetros adicionales [02:04].
Como ambas operaciones son asíncronas (involucran consultas a base de datos), los resolvers se declaran como funciones async y utilizan await para esperar la respuesta.
¿Qué ventaja ofrece seleccionar campos específicos en GraphQL?
Una vez conectada la base de datos, el playground de Apollo Server permite ejecutar queries y elegir exactamente qué campos devolver [02:24]. Por ejemplo, al consultar la lista de productos puedes solicitar únicamente id, name, description y price, y eso es exactamente lo que recibes.
Si después decides que solo necesitas id y name, basta con ajustar la query y el array resultante contendrá exclusivamente esos dos campos [03:10]. Esto contrasta con REST, donde normalmente el servidor devuelve todos los campos del recurso sin importar si el cliente los necesita o no.
¿Cómo funciona la consulta de un producto por su primary key?
Al buscar un producto individual, se envía el parámetro id directamente en la query de GraphQL. El resolver toma ese argumento y ejecuta findOne contra la base de datos en Postgres [03:46]. Si solicitas el producto con id uno, obtienes su nombre y descripción; si cambias a id dos, recibes la información correspondiente. Ya no se trata de datos simulados, sino de una consulta real a la base de datos.
¿Qué sucede con el manejo de errores cuando un producto no existe?
En una arquitectura REST, cuando un producto no se encuentra, el servicio lanza un error 404 Not Found utilizando la librería Boom, que está diseñada para generar errores HTTP con status codes claros [04:30]. El mensaje devuelto es "Product not found".
La pregunta natural es si esa misma librería funciona con GraphQL. La respuesta es sí [05:15]. Apollo Server toma los errores lanzados por Boom y los incorpora como parte de la respuesta de error de GraphQL, incluyendo:
- El mensaje del error.
- Una extensión con el status code y detalles adicionales.
Esto significa que no es necesario reescribir la lógica de manejo de errores. Los mismos mensajes y códigos que ya funcionan en REST se reutilizan directamente en GraphQL [05:48].
¿Por qué es tan eficiente reutilizar servicios entre REST y GraphQL?
La arquitectura por capas permite que la lógica de negocio viva en un solo lugar. Los beneficios concretos son:
- Cero duplicación de código: los resolvers y las rutas REST comparten los mismos servicios.
- Mantenimiento simplificado: cualquier cambio en la lógica de consulta se aplica automáticamente a ambas interfaces.
- Manejo de errores consistente: Boom genera errores HTTP que Apollo Server traduce a errores GraphQL sin configuración adicional.
- Transición gradual: puedes ofrecer REST y GraphQL simultáneamente sin reescribir tu backend.
Con esta conexión establecida, el siguiente paso natural es implementar mutations para la creación de datos, lo que permitirá modificar registros en la base de datos desde GraphQL. Si has trabajado con esta arquitectura, comparte tu experiencia conectando servicios existentes a nuevos resolvers.