Genial curso!, la verdad muy util las herramientas que brinda el profe a lo largo del curso.
Excelente, esto hace mucho mas maleable el trabajo con grphql.
Custom Scalars
En nuestro servidor REST API realizamos validaciones precisas de datos utilizando la librería Joi, pero ¿Cómo lo podemos hacer en consultas GraphQL? Para lograr esto, utilizaremos una técnica llamada custom scalars.
Para utilizar estos tipos de datos, debemos extender GraphQL instalando la librería graphql-scalars:
npminstall graphql-scalars
Esta librería nos permite realizar validaciones nativas en GraphQL, sin necesidad de utilizar librerías adicionales como Joi.
Para implementar nuestros scalars, debemos realizar los siguientes pasos en el archivo index.js de la carpeta graphql:
const{ApolloServer}=require('apollo-server-express');const{ expressMiddleware }=require('apollo-server-express');const{ loadFiles }=require('@graphql-tools/load-files');const{ buildContext }=require('graphql-passport');const resolvers =require('./resolvers');const{typeDefs: scalarsTypeDefs,resolvers: scalarsResolvers }=require('graphql-scalars');constuseGraphql=async(app)=>{// Cargamos los tipos de definición en una única variable dentro de un arrayconst typeDefs =[...awaitloadFiles('./src/**/*.graphql'), scalarsTypeDefs
];// Agregamos los resolvers en una única variable dentro de un arrayconst allResolvers =[ resolvers, scalarsResolvers
];// Los implementamos en nuestro servidor Apolloconst server =newApolloServer({ typeDefs,resolvers: allResolvers,});await server.start(); app.use('/graphql',expressMiddleware(server,{context:async({ req, res })=>buildContext({ req, res })}),);};module.exports= useGraphql;
Luego, podemos comenzar a utilizar los custom scalars en nuestro esquema GraphQL. Aquí hay un ejemplo de cómo se vería en nuestro archivo schema.graphql:
# Tipos de respuesta enviadastypeMutation{# loginlogin(email:EmailAddress!password:String!):AuthResponse}# Esquemas de respuestastypeProduct{id:ID!name:String!price:Float!description:URL!image:String!createdAt:Date!categoryId:ID!category:Category!}typeCategory{id:ID!name:String!image:String!}typeUser{id:ID!email:EmailAddress!role:String!createdAt:Date!}# Esquemas de autenticacióntypeAuthResponse{access_token:String!user:User!}# Inputs# ProductsinputCreateProductDto{name:String!price:Int!description:String!image:URL!categoryId:ID!}inputUpdateProductDto{name:Stringprice:Intdescription:Stringimage:URLcategoryId:ID}# CategoriesinputCreateCategoryDto{name:String!image:URL!}
Excelente, pero ¿Qué sucede si necesitamos realizar una validación adicional, como limitar la longitud de caracteres de un campo? Para esto, podemos utilizar expresiones regulares.
En nuestro archivo resolver.js, podemos hacer lo siguiente:
const{RegularExpression}=require('graphql-scalars');// Creamos nuestro nuevo tipoconstCategoryNameType=newRegularExpression('CategoryNameType',/^[a-zA-Z0-9]{3,8}$/);const resolvers ={Query:{// ...},Mutation:{// ...},// Para agregarlo, lo agregamos como un nuevo tipoCategoryNameType};module.exports= resolvers;
Luego, debemos realizar un paso adicional en nuestro archivo schema.graphql:
# CategoriesinputCreateCategoryDto{# Y ahora podemos usarlo normalmentename:CategoryNameType!image:URL!}# Debemos importarlo de la siguiente manerascalarCategoryNameType
¡Listo! De esta manera, podemos crear tipos de datos complejos utilizando custom scalars en GraphQL.
Scalars Personalizados
add resolver and typedef of library
const{ApolloServer}=require('apollo-server-express');const{ApolloServerPluginLandingPageLocalDefault}=require('apollo-server-core');const{loadFiles}=require('@graphql-tools/load-files')const{typeDefs: typeDefsScalars,resolvers:resolversScalars}=require('graphql-scalars');const{buildContext}=require('graphql-passport')const resolversApp =require('./resolvers')// el ! significa un campo obligatorioconstuseGraphql=async(app)=>{const resolvers =[ resolversApp , resolversScalars];const typeDefs =[...awaitloadFiles('./src/**/*.graphql')/*typesDefs Locals*/,typeDefsScalars]const server =newApolloServer({ typeDefs, resolvers,context:({req,res})=>buildContext({req,res}),plugins:[ApolloServerPluginLandingPageLocalDefault]});await server.start(); server.applyMiddleware({app})}module.exports= useGraphql;
Crear scalar personalizado con Expresiones regulares
const{ login }=require("./auth/auth.resolver")const{ allCategories, categoryById , addCategory}=require("./categories.resolver")const{ product, products ,createProduct,deleteProduct,updateProduct}=require("./product.resolver")const{ getPersons , findPerson, createPerson}=require("./resolver.person")const{RegularExpression}=require('graphql-scalars')// creamos el type con una nueva instancia de RegularExpression constCategoryNameType=newRegularExpression('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// add new type}module.exports= resolvers
GraphQL scalars are predefined scalar types in GraphQL that represent basic data types. Scalars are used to define the shape and type of individual fields in a GraphQL schema. While GraphQL supports custom scalar types, it also provides a set of built-in scalars that cover common data types.
Here are the built-in scalar types in GraphQL:
Int: A signed 32-bit integer.
Float: A signed double-precision floating-point value.
String: A UTF-8 character sequence.
Boolean: Represents a boolean value of true or false.
ID: Represents a unique identifier, often serialized as a string.
These scalar types are the building blocks for defining the data types of field values in GraphQL schemas. They are used to specify the expected types of field arguments and return values.
GraphQL also allows you to define custom scalar types if the built-in scalars do not cover your specific data needs. Custom scalars are useful when dealing with specialized data types such as dates, email addresses, URLs, etc. Custom scalars provide a way to enforce validation and parsing rules for these specific types.
Overall, scalars in GraphQL allow you to define and enforce specific data types for the fields in your API, providing a clear contract for data communication between the client and server.
npm graphql-scalars
It's a popular npm package that provides a collection of commonly used custom scalar types for GraphQL. It simplifies the process of adding custom scalar types to your GraphQL server by providing pre-defined implementations for various data types.
The graphql-scalars library offers a wide range of custom scalar types that are not available as built-in scalars in GraphQL. Some of the commonly used custom scalar types provided by graphql-scalars include:
Date: Represents a date value.
DateTime: Represents a date and time value.
Time: Represents a time value.
EmailAddress: Represents an email address value.
URL: Represents a URL value.
JSON: Represents a JSON object value.
PhoneNumber: Represents a phone number value.
BigInt: Represents an arbitrary precision integer value.
GUID: Represents a globally unique identifier value.
Using the graphql-scalars library, you can easily add these custom scalar types to your GraphQL schema by importing them and including them in your type definitions.
Custom scalar type
We can create a custom scalar type by defining it in the resolvers.
import{RegularExpression}from"graphql-scalars";// the string can have a-z characters in lower/capital case// min length: 3, max length: 8constCategoryNameType=newRegularExpression("CategoryNameType",/^[a-zA-Z-09]{3,8}/);
See ./graphql/resolvers.ts
Then add it to the resolvers:
exportconst resolvers ={Query:{// ...},Mutation:{// ...},// Create new typesCategoryNameType,// <---};
Finally call it inside the schema.graphql file
scalar CategoryNameType
pero como se hace para que esas validaciones las tome después de que valide el jwt?
CUSTOM SCALARS
EnGraphQL*, los scalarspersonalizados son tipos de datosescalaresdefinidos por el usuario que permiten representardatosespecíficos de manera más semántica y precisa en un esquema* GraphQL*. Aunque la especificación de* GraphQLincluyetiposescalarespredeterminados comoInt*,* Float*,* String*,* BooleanyID*, a menudo es necesarioadmitirtipos de datosatómicospersonalizados* (como Fecha, email) o crearversionespersonalizadas de tiposexistentes que realicenvalidacionesadicionales. Los scalarspersonalizados permiten esta flexibilidad al permitir a los desarrolladoresdefinir sus propiostiposescalares para adaptarse a las necesidadesespecíficas de sus aplicaciones. A diferencia de las enumeraciones, que limitan sus valores a una listapredefinida de cadenas, los scalarspersonalizados pueden representar una variedad más amplia de datosatómicos con validacionespersonalizadas.
hay que tener en cuenta que también debemos cambiar el schema para actualizar una categoría
src/graphql/schema.graphql: