La configuration d’un serveur GraphQL dans NestJS permet d’économiser 5x à 10x l’effort avec vanilla NodeJS. NestJS utilise la bibliothèque Apollo standard pour configurer GraphQL. Il prend en charge à la fois le mode normal et le mode de fédération. En mode fédération, nous pouvons configurer des serveurs GraphQL dans chaque microservice, qui peuvent être agrégés à l’aide d’une passerelle tout comme API-Gateway avec des services REST. C’est une très bonne technique si vous exécutez des microservices et que vous souhaitez séparer la responsabilité de chaque service.
NestJS est l’un des frameworks NodeJS les plus puissants disponibles à ce jour. L’une des fonctionnalités intéressantes de NestJS est qu’il permet une intégration facile avec les bases de données, les files d’attente de messages, l’authentification, etc. De plus, il permet aux développeurs de créer des applications à l’aide de NodeJS dans un cadre beaucoup plus strict, robuste et flexible comme Spring Boot/Angular.
Le problème
Tout cela vient avec quelques mises en garde inhérentes à la bibliothèque Apollo. Lors de la configuration de la fédération, vous ne pouvez pas utiliser un abonnement GraphQL.
Vous verrez probablement cette erreur :

Apollo avait proposé une approche pour surmonter ce problème, mais cela complique la situation. Voyons comment résoudre ce problème en utilisant les fonctionnalités de NestJS. Dans l’exemple, j’utilise la première approche du schéma. La même approche peut être mise en œuvre dans l’approche basée sur le code.
La solution
La solution à ce problème consiste à masquer le schéma basé sur un abonnement pour le serveur de fédération et à héberger le GraphQL basé sur un abonnement en tant que serveur GraphQL distinct. Ca a l’air très simple hein ? Pas si simple. Nous allons couvrir la méthode avec quelques étapes simples.
Étape 1 : Classer le schéma
L’étape principale consiste à séparer votre schéma GraphQL en différents fichiers selon les conventions ci-dessous.
- *.graphql : pour la syntaxe GraphQL prise en charge à la fois en mode fédération et en mode normal
- *.graphql.fédération: pour la syntaxe prise en charge uniquement en mode fédération (par exemple, s’étend)
- * .graphql.normal: pour la syntaxe prise en charge uniquement en mode normal (par exemple, abonnement)
Enregistrez le modèle d’abonnement dans n’importe quel « graphql.normal » déposer.

Étape 2 : Configurer le serveur
Configurez app.module.ts avec deux modules GraphQL, un pour le serveur normal et un autre pour le serveur de fédération. Nous devons configurer le module de telle sorte que seul le module de fédération charge le fichier .graphql.federation et que seul le module normal charge le fichier .graphql.normal. Le fichier .graphql doit être chargé par les deux modules.
imports: [
GraphQLModule.forRoot({
debug: false,
playground: true,
path: '/graphql',
typePaths: ['./**/*.{graphql,graphql.normal}'],
installSubscriptionHandlers: true,
}),
GraphQLFederationModule.forRoot({
debug: false,
playground: false,
path: '/graphql-federated',
typePaths: ['./**/*.{graphql,graphql.federation}'],
}),
],
Notez que les chemins de type pour les deux modules sont différents selon notre convention. Le GraphQL normal avec abonnement est maintenant disponible sur /graphql
et le serveur de la passerelle de fédération est disponible sur /graphql-federated
.
Nous ne faisons pas tourner deux serveurs ici. Il s’agit du même serveur express avec deux middleware configurés pour des chemins différents, il n’y aura donc aucun problème de performances.
Étape 3 : L’illusion
Ceci est l’étape la plus importante. Certaines directives dans GraphQL ne fonctionnent qu’en mode fédéré et vice versa. Vous finirez par écrire la version personnalisée du modèle GraphQL dans les fichiers fédérés et normaux. Cela ajoutera le casse-tête des modèles GraphQL en double dans l’application.
Ce problème peut être résolu de manière simple, en utilisant des directives factices !
- Définir un déclaratif pour « clé »
import { SchemaDirectiveVisitor } from 'apollo-server-express';
import { GraphQLField } from 'graphql';
/**
* This is a dummy implementation of the key directive for the normal mode
*/
export class FakeKeyDirective extends SchemaDirectiveVisitor {
/**
* Fake Key definition
* @param _field Field of graphql
*/
visitFieldDefinition(_field: GraphQLField<any, any>) {
_field.args;
}
}
- Incluez-le dans le module.
@Module({
imports: [
GraphQLModule.forRoot({
debug: false,
playground: true,
path: '/graphql',
typePaths: ['./**/*.{graphql,graphql.normal}'],
installSubscriptionHandlers: true,
directiveResolvers: {
key: FakeKeyDirective,
},
}),
GraphQLFederationModule.forRoot({
debug: false,
playground: false,
path: '/graphql-federated',
typePaths: ['./**/*.{graphql,graphql.federation}'],
}),
],
controllers: [AppController],
providers: [AppService, UsersResolver, UserService],
})
export class AppModule {}
- Définir une fausse implémentation. Cela ne doit fonctionner qu’en mode normal, donc le nom du fichier doit se terminer par «
graphql.normal
«
directive @key(fields: String) on OBJECT
- Vous pouvez maintenant définir le modèle à l’aide de la directive @key prise en charge par la fédération, et le modèle fonctionne à la fois dans la fédération et dans le serveur GraphQL normal.
type Department @key(fields: "id") { id: ID! name: String }
Vous pouvez maintenant démarrer la passerelle de fédération, qui écoute le /graphql-federated
, et la fédération fonctionne.
Pour l’abonnement, vous pouvez utiliser n’importe quelle passerelle compatible Websocket comme Nginx, Istio, etc. et vous connecter directement aux microservices
Conclusion
Oui, il est possible d’activer la fédération et l’abonnement pour GraphQL dans NestJS en utilisant une astuce simple plus efficace que la méthode Apollo. Vous pouvez télécharger l’intégralité du code pour votre référence à partir de mon référentiel Github.
Étant donné que vous utilisez une extension de fichier distincte autre que .graphql, votre IDE ne donnera pas le formatage natif GraphQL pour le graphql.normal
et graphql.federation
des dossiers. Il existe un correctif pour cela. Activez simplement les associations de fichiers pour ces extensions.