Scalars
Un type d’objet GraphQL a un nom et des champs, mais à un moment donné, ces champs doivent se résoudre en des données concrètes. C’est là que les types scalars entrent en jeu: ils représentent les feuilles de la requête (lisez-en plus ici). GraphQL inclut les types par défaut suivants: Int
, Float
, String
, Boolean
et ID
. En plus de ces types intégrés, vous pouvez avoir besoin de prendre en charge des types de données atomiques personnalisés (par exemple, Date
).
Code first
L’approche code-first propose cinq scalars dont trois d’entre eux sont des alias simples pour les types GraphQL existants.
ID
(alias pourGraphQLID
) - représente un identifiant unique, souvent utilisé pour récupérer à nouveau un objet ou comme clé pour un cacheInt
(alias pourGraphQLInt
) - un entier signé de 32 bitsFloat
(alias pourGraphQLFloat
) - une valeur à virgule flottante double précision signéeGraphQLISODateTime
- une chaîne de date-heure en UTC (utilisée par défaut pour représenter le typeDate
)GraphQLTimestamp
- un entier signé qui représente la date et l’heure sous forme de nombre de millisecondes écoulées depuis le début de l’époque UNIX
Le GraphQLISODateTime
(par exemple, 2019-12-03T09:54:33Z
) est utilisé par défaut pour représenter le type Date
. Pour utiliser le GraphQLTimestamp
, définissez dateScalarMode
de l’objet buildSchemaOptions
à 'timestamp'
comme suit:
GraphQLModule.forRoot({ buildSchemaOptions: { dateScalarMode: 'timestamp', },})
De même, le GraphQLFloat
est utilisé par défaut pour représenter le type number
. Pour utiliser le GraphQLInt
, définissez numberScalarMode
de l’objet buildSchemaOptions
à 'integer'
comme suit:
GraphQLModule.forRoot({ buildSchemaOptions: { numberScalarMode: 'integer', },})
En outre, vous pouvez créer des scalars personnalisés.
Override a default scalar
Pour créer une implémentation personnalisée pour le scalar Date
, créez simplement une nouvelle classe:
import { Scalar, CustomScalar } from '@nestjs/graphql';import { Kind, ValueNode } from 'graphql';
@Scalar('Date', (type) => Date)export class DateScalar implements CustomScalar<number, Date> { description = 'Type scalar personnalisé Date';
parseValue(value: number): Date { return new Date(value); // valeur du client }
serialize(value: Date): number { return value.getTime(); // valeur envoyée au client }
parseLiteral(ast: ValueNode): Date { if (ast.kind === Kind.INT) { return new Date(ast.value); } return null; }}
Avec cela en place, enregistrez DateScalar
en tant que fournisseur.
@Module({ providers: [DateScalar]})export class CommonModule {}
Maintenant, nous pouvons utiliser le type Date
dans nos classes.
@Field()creationDate: Date;
Import a custom scalar
Pour utiliser un scalar personnalisé, importez-le et enregistrez-le en tant que résolveur. Nous utiliserons le package graphql-type-json
à des fins de démonstration. Ce package npm définit un type scalar JSON
GraphQL.
Commencez par installer le package:
$ npm i --save graphql-type-json
Une fois le package installé, nous passons un résolveur personnalisé à la méthode forRoot()
:
import GraphQLJSON from 'graphql-type-json';
@Module({ imports: [ GraphQLModule.forRoot({ resolvers: { JSON: GraphQLJSON }, }), ],})export class AppModule {}
Maintenant, nous pouvons utiliser le type JSON
dans nos classes.
@Field(() => GraphQLJSON)info: JSON;
Pour un ensemble de scalars utiles, jetez un œil au package graphql-scalars.
Create a custom scalar
Pour définir un scalar personnalisé, créez une nouvelle instance de GraphQLScalarType
. Nous allons créer un scalar personnalisé UUID
.
const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function validate(uuid: unknown): string | never { if (typeof uuid !== "string" || !regex.test(uuid)) { throw new Error("invalid uuid"); } return uuid;}
export const CustomUuidScalar = new GraphQLScalarType({ name: 'UUID', description: 'Un simple parseur UUID', serialize: (value) => validate(value), parseValue: (value) => validate(value), parseLiteral: (ast) => validate(ast.value),});
Nous passons un résolveur personnalisé à la méthode forRoot()
:
@Module({ imports: [ GraphQLModule.forRoot({ resolvers: { UUID: CustomUuidScalar }, }), ],})export class AppModule {}
Maintenant, nous pouvons utiliser le type UUID
dans nos classes.
@Field(() => CustomUuidScalar)uuid: string;
Schema first
Pour définir un scalar personnalisé (lisez-en plus sur les scalars ici), créez une définition de type et un résolveur dédié. Ici (comme dans la documentation officielle), nous utiliserons le package graphql-type-json
à des fins de démonstration. Ce package npm définit un type scalar JSON
GraphQL.
Commencez par installer le package:
$ npm i --save graphql-type-json
Une fois le package installé, nous passons un résolveur personnalisé à la méthode forRoot()
:
import GraphQLJSON from 'graphql-type-json';
@Module({ imports: [ GraphQLModule.forRoot({ typePaths: ['./**/*.graphql'], resolvers: { JSON: GraphQLJSON }, }), ],})export class AppModule {}
Maintenant, nous pouvons utiliser le scalar JSON
dans nos définitions de types:
scalar JSON
type Foo { field: JSON}
Une autre méthode pour définir un type scalar est de créer une classe simple. Supposons que nous voulons améliorer notre schéma avec le type Date
.
import { Scalar, CustomScalar } from '@nestjs/graphql';import { Kind, ValueNode } from 'graphql';
@Scalar('Date')export class DateScalar implements CustomScalar<number, Date> { description = 'Type scalar personnalisé Date';
parseValue(value: number): Date { return new Date(value); // valeur du client }
serialize(value: Date): number { return value.getTime(); // valeur envoyée au client }
parseLiteral(ast: ValueNode): Date { if (ast.kind === Kind.INT) { return new Date(ast.value); } return null; }}
Avec cela en place, enregistrez DateScalar
en tant que fournisseur.
@Module({ providers: [DateScalar]})export class CommonModule {}
Maintenant, nous pouvons utiliser le scalar Date
dans les définitions de types:
scalar Date
Par défaut, la définition TypeScript générée pour tous les scalars est any
- ce qui n’est pas particulièrement sûr en termes de types. Mais, vous pouvez configurer la manière dont Nest génère des typings pour vos scalars personnalisés lorsque vous spécifiez comment générer des types:
import { GraphQLDefinitionsFactory } from '@nestjs/graphql';import { join } from 'path';
const definitionsFactory = new GraphQLDefinitionsFactory();
definitionsFactory.generate({ typePaths: ['./src/**/*.graphql'], path: join(process.cwd(), 'src/graphql.ts'), outputAs: 'class', defaultScalarType: 'unknown', customScalarTypeMapping: { DateTime: 'Date', BigNumber: '_BigNumber', }, additionalHeader: "import _BigNumber from 'bignumber.js'",});
Maintenant, étant donné les types scalars personnalisés GraphQL suivants:
scalar DateTimescalar BigNumberscalar Payload
Nous verrons maintenant les définitions TypeScript générées suivantes dans src/graphql.ts
:
import _BigNumber from 'bignumber.js';
export type DateTime = Date;export type BigNumber = _BigNumber;export type Payload = unknown;
Ici, nous avons utilisé la propriété customScalarTypeMapping
pour fournir une map des types que nous voulons déclarer pour nos scalars personnalisés. Nous avons également fourni une propriété additionalHeader
afin que nous puissions ajouter toutes les importations nécessaires pour ces définitions de type. Enfin, nous avons ajouté un defaultScalarType
de 'unknown'
, de sorte que tous les scalars personnalisés non spécifiés dans customScalarTypeMapping
seront aliased à unknown
au lieu de any
(ce que TypeScript recommande d’utiliser depuis 3.0 pour une sécurité de type accrue).