Excelente característica, incentiva a la reutilización de consultas simples y reduce el números de consultas complejas que surgen usando inner join en las consultas sql.
Introducción
¿Qué es GraphQL?
Proyecto: tienda online con GraphQL
Análisis de la API REST (sin GraphQL)
Fundamentos de GraphQL
Tu primera API GraphQL
GraphQL desde Insomnia y Postman
Tipado en GraphQL
Sistema de tipado
Scalar types
Listas y non-null types
Object types and fields
Archivos .graphql (mejor developer experience)
GraphQL en la Tienda con Express.js
Product resolvers
Conectado a ProductService
Mutations and Inputs
Variables y alias
Update and Delete
Anidamiento
Autenticación con GraphQL y JSON Web Tokens
Login
Crear categoría
GraphQL con JWT
Validar roles
Custom Scalars
Bonus
Anidamiento dinámico
Conclusiones
GraphQL vs. API REST
Toma el Curso Avanzado de Node.js con GraphQL
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial
Antes: $249
Paga en 4 cuotas sin intereses
Termina en:
Nicolas Molina
Aportes 7
Preguntas 1
Excelente característica, incentiva a la reutilización de consultas simples y reduce el números de consultas complejas que surgen usando inner join en las consultas sql.
Para entender como lograr un anidamiento dinámico, primero tenemos que lograr que cuando le pidamos a GraphQL una categoría específica, nos mande los productos de esta categoría, veamos como:
Añadimos en el esquema la nueva query:
type Query {
# ...
# categories
category(id: ID!): Category
}
type Category {
# relación entre productos
product: [Product]
}
Ahora vamos al category.resolvers.js y añadimos la siguiente lógica:
const getCategory = (_, { id }) => {
return service.findOne(id)
}
module.exports = {
// ...
getCategory
}
Ahora añadimos la función a los resolvers:
const { addCategory, getCategory } = require('./category.resolvers')
const resolvers = {
Query: {
// ...
category: getCategory
},
Mutation: {
// ...
},
};
module.exports = resolvers
Con esto, si realizamos una consulta solicitando los productos de una categoría, obtendremos los resultados correctamente.
Sin embargo, si observamos los servicios de categoría, notaremos que la relación siempre se carga, incluso si no la solicitamos en la consulta. ¿Cómo podemos solucionar esto?
GraphQL ofrece una herramienta para resolver este problema. Podemos definir un campo como un resolver, lo que nos permite ejecutar código solo cuando ese campo es requerido.
Teniendo esto en cuenta, veamos cómo añadir esta lógica en nuestro servidor:
Primero vamos a nuestro servicio de productos y vamos a crear la función que nos va a enviar estos datos solo cuando los pidamos
class ProductsService {
// ...
async getByCategory(id) {
return await models.Product.findAll({ where: { categoryId: id }});
}
}
Ahora vamos a nuestro **product.resolver**
y vamos a crear lo siguiente:
const ProductServices = require('../services/product.service')
const service = new ProductServices
// ...
// el parent es el campo que ignorábamos
// Lo utilizamos cuando ejecutamos campos de forma dinámica
const getProdutsByCategory = (parent) => {
const id = parent.dataValues.id;
return service.getByCategory(id)
}
module.exports = {
// ...
getProdutsByCategory
}
Ahora vamos al resolver principal a hacer lo siguiente:
const { /* ... */ getProductsByCategory } = require('./product.resolvers')
const resolvers = {
Query: {
// ...
},
Mutation: {
// ...
},
// Hacemos que el campo 'products' de 'Category' se ejecute como un resolver
Category: {
// En el campo 'products', llamamos a la función 'getProductsByCategory'
products: getProductsByCategory
}
};
Hay que tener en cuenta que esta consulta solo se ejecuta si enviamos el campo products, de lo contrarío, no lo va a hacer. Con esto no estamos haciendo consultas innecesarias en nuestra base de datos.
si en el resultado final les arroja un error
es porque en el video no se alcanza a ver que el id va dentro y no fuera
return service.getByCategory(id);
se crea un type que rotorne otro type que este relacionado en la base de datos
type Category {
id: ID
name: String,
image: String,
createdAt: String
products:[Product!]!
}
type Query {
allCategories: [Category]
categoryById(id:ID): Category
}
type Product {
id:ID!
name:String!
price:Float!
description:String!
createdAt:String!
image:URL!
category:Category
}
definimos ese type en nuestros resolvers, por lo tanto el type debe llamarse igual al definido
const { login } = require("./auth/auth.resolver")
const { allCategories, categoryById , addCategory} = require("./categories.resolver")
const { product, products ,createProduct,deleteProduct,updateProduct, getProductByCategory} = require("./product.resolver")
const { getPersons , findPerson, createPerson} = require("./resolver.person")
const {RegularExpression} = require('graphql-scalars')
const CategoryNameType= new RegularExpression('CategoryNameType', /^[a-zA-Z0-9]{3,8}$/);
const resolvers= {
Query:{
saludo: ()=> 'hola mundillo de internet',
persons:getPersons,
findPerson,
allCategories,
categoryById,
product,
products
},
Mutation:{
createPerson,
createProduct,
deleteProduct,
updateProduct,
addCategory,
login
},
CategoryNameType,
Category: {
products: getProductByCategory
}
}
module.exports = resolvers
getProductByCategory hace la peticion a la base de datos
const getProductByCategory =async(root,_)=>{
// root es el objeto padre del cual ha sido llamado el resolver es decir: Category
return await service.getByCategory(root.dataValues.id)
// creamos un metodo en el servicio que retorne los productos relacionados a la categoria
// por medio del id
// asi solo el resolver se ejecuta si en la consulta son requeridos los productos
}
metodo del servicio
async getByCategory(idCategory){
return await models.Product.findAll({where:{categoryId:idCategory}})
}
It’s possible to modify the output of a property inside a schema type. To do so, we can use the parent
param, which is the first parameter passed to a resolver.
We’ll modify the products
property from the Category
type which is already created in schema.graphql
. So we must do this in the resolvers:
export const resolvers = {
Query: {
category: getCategory, // the parent param will contain what this resolver returns
},
Mutation: {
// ...
},
// The same name as in the schema.graphql (Category)
Category: {
products: getProductsOfCategory, // <--- modifying its output
},
};
We call Category and modify the output of the products
property.
<br>
The function getProductsOfCategory
it’s declared inside product.resolvers.ts
file. This is what it does:
const service = new ProductsService();
export const getProductsOfCategory = (parent: any) => {
const categoryId = parent.dataValues.id;
return service.findProductsByCategory(categoryId);
};
So basically we use the parent
parameter, which returns the data that is already retrieved by the category
query itself. In the parent we can find the categoryId that we’ll use to make another query to the db, this time only retrieving the products from that specific category.
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?