No tienes acceso a esta clase

¬°Contin√ļa aprendiendo! √önete y comienza a potenciar tu carrera

Custom Scalars

21/24
Recursos

Link de interés:

GraphQL Scalars

Aportes 7

Preguntas 1

Ordenar por:

¬ŅQuieres ver m√°s aportes, preguntas y respuestas de la comunidad?

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.

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 obligatorio

const  useGraphql= async (app)=>{
  const resolvers = [ resolversApp , resolversScalars];

  const typeDefs = [ ...await loadFiles('./src/**/*.graphql')/*typesDefs Locals*/ ,typeDefsScalars]

  const server = new ApolloServer({
    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 

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 // add new type
}

module.exports = resolvers

utilizamos nuestro scalars en nuestros typeDefs


scalar CategoryNameType
input CreateCategory {
  name: CategoryNameType!,
  image: URL!,
  # products:[Product]
 }

el type URL retorna es un objecto con la url desustrurada, por lo tanto se debe sacar la url del objeto en la propiedad href

const addCategory = async (root, {dto},context)=>{
  const user = await checkJwtGql(context) //validate jtw
  checkRoleGql(user,'admin') ; // validate Role
  // console.log(dto)
  const newCategory = await service.create({
    ...dto,
    image:dto.image.href// url Image
  });
  return newCategory;
}

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:

npm install 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');

const useGraphql = async (app) => {
	 // Cargamos los tipos de definici√≥n en una √ļnica variable dentro de un array
  const typeDefs = [
    ...await loadFiles('./src/**/*.graphql'),
    scalarsTypeDefs
  ];

  // Agregamos los resolvers en una √ļnica variable dentro de un array
  const allResolvers = [
    resolvers,
    scalarsResolvers
  ];

  // Los implementamos en nuestro servidor Apollo
  const server = new ApolloServer({
    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 enviadas

type Mutation {
  # login
  login(email: EmailAddress! password: String!): AuthResponse
}

# Esquemas de respuestas
type Product {
  id: ID!
  name: String!
  price: Float!
  description: URL!
  image: String!
  createdAt: Date!
  categoryId: ID!
  category: Category!
}

type Category {
  id: ID!
  name: String!
  image: String!
}

type User {
  id: ID!
  email: EmailAddress!
  role: String!
  createdAt: Date!
}

# Esquemas de autenticación
type AuthResponse {
  access_token: String!
  user: User!
}

# Inputs

# Products
input CreateProductDto {
  name: String!
  price: Int!
  description: String!
  image: URL!
  categoryId: ID!
}

input UpdateProductDto {
  name: String
  price: Int
  description: String
  image: URL
  categoryId: ID
}

# Categories
input CreateCategoryDto {
  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 tipo
const CategoryNameType = new RegularExpression('CategoryNameType', /^[a-zA-Z0-9]{3,8}$/);

const resolvers = {
  Query: {
    // ...
  },
  Mutation: {
    // ...
  },
  // Para agregarlo, lo agregamos como un nuevo tipo
  CategoryNameType
};

module.exports = resolvers;

Luego, debemos realizar un paso adicional en nuestro archivo schema.graphql:

# Categories
input CreateCategoryDto {
  # Y ahora podemos usarlo normalmente
  name: CategoryNameType!
  image: URL!
}

# Debemos importarlo de la siguiente manera
scalar CategoryNameType

¬°Listo! De esta manera, podemos crear tipos de datos complejos utilizando custom scalars en GraphQL.

**CUSTOM SCALARS** *En* **GraphQL***, los **scalars** **personalizados** son **tipos** de **datos** **escalares** **definidos** por el **usuario** que permiten **representar** **datos** **específicos** de manera más **semántica** y **precisa** en un **esquema*** **GraphQL***. **Aunque** la **especificación** de* **GraphQL** ***incluye** **tipos** **escalares** **predeterminados** como* **Int***,* **Float***,* **String***,* **Boolean** *y* **ID***, a **menudo** es **necesario** **admitir** **tipos** de **datos** **atómicos** **personalizados*** (como Fecha, email) *o **crear** **versiones** **personalizadas** de **tipos** **existentes** que **realicen** **validaciones** **adicionales**. Los **scalars** **personalizados** permiten esta **flexibilidad** al permitir a los **desarrolladores** **definir** sus **propios** **tipos** **escalares** para **adaptarse** a las **necesidades** **específicas** de sus **aplicaciones**. A **diferencia** de las **enumeraciones**, que **limitan** sus **valores** a una **lista** **predefinida** de **cadenas**, los **scalars** **personalizados** pueden **representar** una **variedad** más **amplia** de **datos** **atómicos** con **validaciones** **personalizadas**.*

GraphQL Scalars

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: 8
const CategoryNameType = new RegularExpression(
  "CategoryNameType",
  /^[a-zA-Z-09]{3,8}/
);

See ./graphql/resolvers.ts

Then add it to the resolvers:

export const resolvers = {
  Query: {
    // ...
  },
  Mutation: {
   // ...
  },

  // Create new types
  CategoryNameType,  // <---
};

Finally call it inside the schema.graphql file

scalar CategoryNameType

hay que tener en cuenta que también debemos cambiar el schema para actualizar una categoría
src/graphql/schema.graphql:

input UpdateCategoryDto {
  name: String
  image: URL
}

y su resolver
src/graphql/category.resolvers.js:

const updateCategory = (_, { id, dto })=> {
  return service.update(id, {
    ...dto,
    image: dto.image.href
  })
}

esto debido a que si no lo hacemos, podríamos modificar la categoría pasándole un String cualquiera y seria permitido