Exploitation de la puissance de TypeScript et GraphQL
GraphQL est un langage de requête puissant pour les API et un environnement d’exécution pour satisfaire ces requêtes avec vos données existantes. C’est une approche élégante qui résout de nombreux problèmes typiquement rencontrés avec les API REST. Pour plus de contexte, nous vous recommandons de lire cette comparaison entre GraphQL et REST. GraphQL combiné avec TypeScript vous aide à développer une meilleure sécurité de type avec vos requêtes GraphQL, vous offrant une typage de bout en bout.
Dans ce chapitre, nous supposons une compréhension de base de GraphQL et nous nous concentrons sur la façon de travailler avec le module intégré @nestjs/graphql
. Le GraphQLModule
peut être configuré pour utiliser le serveur Apollo (avec le pilote @nestjs/apollo
) et Mercurius (avec le @nestjs/mercurius
). Nous fournissons des intégrations officielles pour ces packages GraphQL éprouvés afin de fournir un moyen simple d’utiliser GraphQL avec Nest (voir plus d’intégrations ici).
Vous pouvez également construire votre propre conducteur dédié (lisez-en plus ici).
Installation
Commencez par installer les packages requis :
# Pour Express et Apollo (par défaut)$ npm i @nestjs/graphql @nestjs/apollo @apollo/server graphql
# Pour Fastify et Apollo# npm i @nestjs/graphql @nestjs/apollo @apollo/server @as-integrations/fastify graphql
# Pour Fastify et Mercurius# npm i @nestjs/graphql @nestjs/mercurius graphql mercurius
Vue d’ensemble
Nest offre deux façons de construire des applications GraphQL, les méthodes code first et schema first. Vous devriez choisir celle qui fonctionne le mieux pour vous. La plupart des chapitres de cette section GraphQL sont divisés en deux parties principales : celle que vous devez suivre si vous adoptez code first, et l’autre à utiliser si vous adoptez schema first.
Avec l’approche code first, vous utilisez des décorateurs et des classes TypeScript pour générer le schéma GraphQL correspondant. Cette approche est utile si vous préférez travailler exclusivement avec TypeScript et éviter de passer d’une syntaxe de langage à l’autre.
Avec l’approche schema first, la source de vérité est les fichiers SDL (Schema Definition Language) GraphQL. SDL est une manière indépendante du langage de partager des fichiers de schéma entre différentes plateformes. Nest génère automatiquement vos définitions TypeScript (en utilisant soit des classes, soit des interfaces) basées sur les schémas GraphQL pour réduire la nécessité d’écrire du code boilerplate redondant.
Une fois les packages installés, nous pouvons importer le GraphQLModule
et le configurer avec la méthode statique forRoot()
.
import { Module } from '@nestjs/common';import { GraphQLModule } from '@nestjs/graphql';import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
@Module({ imports: [ GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, }), ],})export class AppModule {}
La méthode forRoot()
prend un objet d’options en argument. Ces options sont passées à l’instance de conducteur sous-jacente (lisez-en plus sur les paramètres disponibles ici : Apollo et Mercurius). Par exemple, si vous souhaitez désactiver le playground
et désactiver le mode debug
(pour Apollo), passez les options suivantes :
import { Module } from '@nestjs/common';import { GraphQLModule } from '@nestjs/graphql';import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
@Module({ imports: [ GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, playground: false, }), ],})export class AppModule {}
Dans ce cas, ces options seront transférées au constructeur ApolloServer
.
GraphQL Playground
Le playground est un IDE GraphQL interactif et graphique disponible par défaut à la même URL que le serveur GraphQL lui-même. Pour accéder à l’environnement de développement, vous avez besoin d’un serveur GraphQL configuré et en cours d’exécution. Pour le voir maintenant, vous pouvez installer et construire l’exemple fonctionnel ici. Alternativement, si vous suivez ces exemples de code, une fois que vous avez complété les étapes dans le chapitre des Resolvers, vous pourrez accéder au playground.
Avec cela en place, et avec votre application en cours d’exécution en arrière-plan, vous pouvez ensuite ouvrir votre navigateur web et naviguer vers http://localhost:3000/graphql
(l’hôte et le port peuvent varier en fonction de votre configuration). Vous verrez alors le playground GraphQL.
L’intégration @nestjs/mercurius
n’expédie pas avec l’intégration du GraphQL Playground intégrée. Au lieu de cela, vous pouvez utiliser GraphiQL (définissez graphiql: true
).
Points de terminaison multiples
Une autre fonctionnalité utile du module @nestjs/graphql
est la possibilité de servir plusieurs points de terminaison à la fois. Cela vous permet de décider quels modules doivent être inclus dans quel point de terminaison. Par défaut, GraphQL
recherche des resolvers dans toute l’application. Pour limiter cette recherche à un sous-ensemble de modules, utilisez la propriété include
.
GraphQLModule.forRoot({ include: [CatsModule],}),
Si vous utilisez le @apollo/server
avec le package @as-integrations/fastify
avec plusieurs points de terminaison GraphQL dans une seule application, assurez-vous d’activer le paramètre disableHealthCheck
dans la configuration du GraphQLModule
.
Code First
Dans l’approche code first, vous utilisez des décorateurs et des classes TypeScript pour générer le schéma GraphQL correspondant.
Pour utiliser l’approche code first, commencez par ajouter la propriété autoSchemaFile
à l’objet d’options :
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: join(process.cwd(), 'src/schema.gql'),}),
La valeur de la propriété autoSchemaFile
est le chemin où votre schéma généré automatiquement sera créé. Alternativement, le schéma peut être généré à la volée en mémoire. Pour activer cela, définissez la propriété autoSchemaFile
sur true
:
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: true,}),
Par défaut, les types dans le schéma généré seront dans l’ordre dans lequel ils sont définis dans les modules inclus. Pour trier le schéma de manière lexicographique, définissez la propriété sortSchema
sur true
:
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: join(process.cwd(), 'src/schema.gql'), sortSchema: true,}),
Exemple
Un exemple fonctionnel de code first est disponible ici.
Schema First
Pour utiliser l’approche schema first, commencez par ajouter une propriété typePaths
à l’objet d’options. La propriété typePaths
indique où le GraphQLModule
devrait chercher les fichiers de définition de schéma SDL GraphQL que vous écrivez. Ces fichiers seront combinés en mémoire ; cela vous permet de diviser vos schémas en plusieurs fichiers et de les situer près de leurs resolvers.
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, typePaths: ['./**/*.graphql'],}),
Vous devrez également avoir des définitions TypeScript (classes et interfaces) qui correspondent aux types SDL GraphQL. Créer les définitions TypeScript correspondantes à la main est redondant et fastidieux. Cela nous laisse sans source unique de vérité : chaque changement apporté dans SDL nous oblige à ajuster également les définitions TypeScript. Pour remédier à cela, le package @nestjs/graphql
peut générer automatiquement des définitions TypeScript à partir de l’arbre de syntaxe abstraite (AST). Pour activer cette fonctionnalité, ajoutez les options definitions
lors de la configuration du GraphQLModule
.
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, typePaths: ['./**/*.graphql'], definitions: { path: join(process.cwd(), 'src/graphql.ts'), },}),
La propriété path
de l’objet definitions
indique où enregistrer la sortie TypeScript générée. Par défaut, tous les types TypeScript générés sont créés sous forme d’interfaces. Pour générer des classes, spécifiez la propriété outputAs
avec une valeur de class
.
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, typePaths: ['./**/*.graphql'], definitions: { path: join(process.cwd(), 'src/graphql.ts'), outputAs: 'class', },}),
L’approche ci-dessus génère dynamiquement les définitions TypeScript chaque fois que l’application démarre. Alternativement, il peut être préférable de créer un script simple pour les générer à la demande.
Intégration Mercurius
Au lieu d’utiliser Apollo, les utilisateurs de Fastify (lisez-en plus ici) peuvent utiliser le pilote @nestjs/mercurius
.
import { Module } from '@nestjs/common';import { GraphQLModule } from '@nestjs/graphql';import { MercuriusDriver, MercuriusDriverConfig } from '@nestjs/mercurius';
@Module({ imports: [ GraphQLModule.forRoot<MercuriusDriverConfig>({ driver: MercuriusDriver, graphiql: true, }), ],})export class AppModule {}
Intégrations tierces
Accéder au schéma généré
Dans certaines circonstances (par exemple, pour des tests de bout en bout), vous voudrez peut-être obtenir une référence à l’objet schéma généré.
const { schema } = app.get(GraphQLSchemaHost);
Configuration asynchrone
Lorsque vous devez passer des options de module de manière asynchrone au lieu de statiquement, utilisez la méthode forRootAsync()
. Comme pour la plupart des modules dynamiques, Nest fournit plusieurs techniques pour gérer la configuration asynchrone.
GraphQLModule.forRootAsync<ApolloDriverConfig>({ driver: ApolloDriver, useFactory: () => ({ typePaths: ['./**/*.graphql'], }),}),
GraphQLModule.forRootAsync<ApolloDriverConfig>({ driver: ApolloDriver, useClass: GqlConfigService,}),
@Injectable()class GqlConfigService implements GqlOptionsFactory { createGqlOptions(): ApolloDriverConfig { return { typePaths: ['./**/*.graphql'], }; }}
GraphQLModule.forRootAsync<ApolloDriverConfig>({ imports: [ConfigModule], useExisting: ConfigService,}),