Organización de Resolvers con el Principio de Responsabilidad Única

Clase 11 de 24Curso de GraphQL con Node.js

Resumen

¿Cómo dividir los resolvers para mejorar la escalabilidad y mantenimiento?

Dividir los resolvers en archivos específicos es crucial para mantener y escalar un sistema de manera efectiva. Esta práctica asegura que cada resolver tenga un dominio y responsabilidad específicos, facilitando el manejo del código y mejorando su legibilidad.

Al igual que en las rutas, donde cada endpoint tiene su archivo respectivo, en GraphQL podemos hacer lo mismo con los resolvers. Por ejemplo, crear un archivo ProductResolvers.js para contener todas las funciones relacionadas con los productos. Así, podemos empezar a aislar funciones específicas.

¿Cómo se crean los resolvers para productos?

Para implementar resolvers separados, sigue los pasos para crear dos funciones básicas: obtener un producto y obtener una lista de productos. Es crucial usar la técnica de desestructuración para manejar argumentos. Esta técnica permite extraer elementos específicos directamente de los argumentos.

const getProduct = (parent, { id }) => {
  // Aquí va la lógica para obtener un producto usando el id proporcionado.
  return product; // producto previamente obtenido.
};

const getProducts = () => {
  return []; // Por ahora, retornamos un arreglo vacío.
};

module.exports = { getProduct, getProducts };

En este ejemplo, getProduct recibe un id que se utiliza para recuperar y devolver el producto específico. Por otra parte, getProducts devuelve una lista vacía, con la idea de incorporar lógica de servicios más adelante.

¿Cómo conectar los resolvers con el archivo principal?

Es importante crear un archivo Resolvers.js, que sirva como directorio central para agrupar y exportar todos los resolvers. Este archivo se importa a index.js, limpiando así su estructura.

const { getProduct, getProducts } = require('./ProductResolvers');

module.exports = {
  Product: getProduct,
  Products: getProducts,
  // aquí pueden añadirse más resolvers de diferentes entidades
};

Esta estructura modular delega responsabilidades, manteniendo el código organizado. Ahora, index.js únicamente necesita importar los resolvers centralizados:

const resolvers = require('./Resolvers');

¿Cómo configurar las queries y argumentos en GraphQL?

En GraphQL, las queries representan funciones que se ejecutan para recuperar datos. Es crucial alinear los nombres de las funciones con las entidades que se representan.

Nombres de funciones y queries en GraphQL

En vez de usar nombres de funciones como getProduct o getProducts, se recomienda usar Product y Products, respectivamente. Al hacer match entre el esquematizado y los resolvers, obtenemos una estructura limpia que refleja la naturaleza de las entidades, haciendo el código más intuitivo.

type Query {
  Product(id: ID!): Product
  Products: [Product!]!
}

En este esquema:

  • Product requiere un id y devuelve una única entidad de producto, o null si no se encuentra.
  • Products devuelve una lista de productos, garantizando que no contenga nulos.

¿Está funcionando correctamente nuestro sistema?

Una vez configurado, es vital usar una herramienta como GraphQL Playground para probar las queries. Ejecuta una query de ejemplo para comprobar su correcto funcionamiento:

query GetSingleProduct($id: ID!) {
  Product(id: $id) {
    name
    price
  }
}

Si el resolver está correcto, deberías obtener los detalles del producto con el ID especificado. Para Products, una query estructurada devolverá una lista vacía hasta integrar la lógica de servicios:

query {
  Products {
    name
    id
  }
}

La arquitectura planteada permite escalar el sistema fácilmente, incluso cuando los resolvers se dividen. Aunque nuestro resolver todavía no está conectado a la capa de servicios para manejar los datos de la base de datos, este es el próximo paso para un sistema completo y funcional.