Passer au contenu

Plugin CLI

TypeScript a un système de réflexion des métadonnées qui présente plusieurs limitations, rendant, par exemple, impossible de déterminer quelles propriétés compose une classe ou de reconnaître si une propriété donnée est optionnelle ou requise. Cependant, certaines de ces contraintes peuvent être abordées au moment de la compilation. Nest fournit un plugin qui améliore le processus de compilation TypeScript afin de réduire la quantité de code répétitif nécessaire.

Vue d’ensemble

Le plugin Swagger annotera automatiquement :

  • toutes les propriétés DTO avec @ApiProperty sauf si @ApiHideProperty est utilisé
  • la propriété required en fonction du point d’interrogation (par exemple, name?: string définira required: false)
  • la propriété type ou enum en fonction du type (prend également en charge les tableaux)
  • la propriété default basée sur la valeur par défaut assignée
  • plusieurs règles de validation basées sur les décorateurs de class-validator (si classValidatorShim est défini sur true)
  • ajouter un décorateur de réponse à chaque point final avec un statut approprié et type (modèle de réponse)
  • générer des descriptions pour les propriétés et les points finaux basées sur les commentaires (si introspectComments est défini sur true)
  • générer des valeurs d’exemple pour les propriétés basées sur les commentaires (si introspectComments est défini sur true)

Veuillez noter que vos noms de fichiers doivent avoir l’un des suffixes suivants : ['.dto.ts', '.entity.ts'] (par exemple, create-user.dto.ts) afin d’être analysés par le plugin.

Si vous utilisez un suffixe différent, vous pouvez ajuster le comportement du plugin en spécifiant l’option dtoFileNameSuffix.

Auparavant, si vous vouliez fournir une expérience interactive avec l’interface utilisateur Swagger, vous deviez dupliquer une grande quantité de code pour faire savoir au package comment vos modèles/composants devaient être déclarés dans la spécification. Par exemple, vous pourriez définir une simple classe CreateUserDto comme suit :

Définition de la classe CreateUserDto
export class CreateUserDto {
@ApiProperty()
email: string;
@ApiProperty()
password: string;
@ApiProperty({ enum: RoleEnum, default: [], isArray: true })
roles: RoleEnum[] = [];
@ApiProperty({ required: false, default: true })
isEnabled?: boolean = true;
}

Bien que cela ne soit pas un problème significatif avec des projets de taille moyenne, cela devient verbeux et difficile à maintenir une fois que vous avez un grand ensemble de classes.

En activant le plugin Swagger, la définition de classe ci-dessus peut être déclarée simplement :

Définition simplifiée de la classe CreateUserDto
export class CreateUserDto {
email: string;
password: string;
roles: RoleEnum[] = [];
isEnabled?: boolean = true;
}

Ainsi, si vous prévoyez de vous fier aux annotations automatiques pour la génération de documentations tout en souhaitant des validations à l’exécution, alors les décorateurs de validation de classe sont toujours nécessaires.

Le plugin ajoute les décorateurs appropriés à la volée en fonction de l’Arbre de syntaxe abstraite. Ainsi, vous n’aurez pas à vous battre avec les décorateurs @ApiProperty éparpillés dans le code.

Introspection des commentaires

Avec la fonctionnalité d’introspection des commentaires activée, le plugin CLI générera des descriptions et des valeurs d’exemple pour les propriétés en fonction des commentaires.

Par exemple, étant donné une propriété roles :

Exemple de propriété roles
/**
* A list of user's roles
* @example ['admin']
*/
@ApiProperty({
description: `A list of user's roles`,
example: ['admin'],
})
roles: RoleEnum[] = [];

Vous devez dupliquer à la fois la description et les valeurs d’exemple. Avec introspectComments activé, le plugin CLI peut extraire ces commentaires et fournir automatiquement des descriptions (et des exemples, si définis) pour les propriétés. Maintenant, la propriété ci-dessus peut être déclarée simplement comme suit :

Propriété simplifiée roles
/**
* A list of user's roles
* @example ['admin']
*/
roles: RoleEnum[] = [];

Il existe dtoKeyOfComment et controllerKeyOfComment, options de plugin que vous pouvez utiliser pour personnaliser comment le plugin définira la valeur pour les décorateurs ApiProperty et ApiOperation respectivement. Prenons un exemple :

Exemple de contrôleur avec introspection
export class SomeController {
/**
* Create some resource
*/
@Post()
create() {}
}

Par défaut, ces options sont définies sur "description". Cela signifie que le plugin assignera "Create some resource" à la clé description sur l’opérateur ApiOperation. Ainsi :

Définition de l'opération de création
@ApiOperation({ description: "Create some resource" })

Utilisation du plugin CLI

Pour activer le plugin, ouvrez nest-cli.json (si vous utilisez Nest CLI) et ajoutez la configuration suivante dans plugins :

Configuration de plugin dans nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/swagger"]
}
}

Vous pouvez utiliser la propriété options pour personnaliser le comportement du plugin.

Options personnalisées du plugin
"plugins": [
{
"name": "@nestjs/swagger",
"options": {
"classValidatorShim": false,
"introspectComments": true
}
}
]

La propriété options doit remplir l’interface suivante :

Interface des options de plugin
export interface PluginOptions {
dtoFileNameSuffix?: string[];
controllerFileNameSuffix?: string[];
classValidatorShim?: boolean;
dtoKeyOfComment?: string;
controllerKeyOfComment?: string;
introspectComments?: boolean;
}
OptionPar défautDescription
dtoFileNameSuffix['.dto.ts', '.entity.ts']Suffixes de fichiers DTO (Objet de transfert de données)
controllerFileNameSuffix.controller.tsSuffixe de fichiers de contrôleur
classValidatorShimtrueS’il est défini sur true, le module réutilisera les décorateurs de validation class-validator
dtoKeyOfComment'description'La clé de propriété pour définir le texte de commentaire sur ApiProperty.
controllerKeyOfComment'description'La clé de propriété pour définir le texte de commentaire sur ApiOperation.
introspectCommentsfalseS’il est défini sur true, le plugin générera des descriptions et des valeurs d’exemple pour les propriétés basées sur les commentaires

Assurez-vous de supprimer le dossier /dist et de reconstruire votre application chaque fois que les options du plugin sont mises à jour. Si vous n’utilisez pas le CLI mais avez plutôt une configuration personnalisée webpack, vous pouvez utiliser ce plugin en combinaison avec ts-loader :

Configuration pour ts-loader
getCustomTransformers: (program) => ({
before: [
require('@nestjs/swagger/plugin').before({}, program),
],
}),

Constructeur SWC

Pour les configurations standard (non-monorepo), pour utiliser les plugins CLI avec le constructeur SWC, vous devez activer la vérification des types, comme décrit ici.

Fenêtre de terminal
$ nest start -b swc --type-check

Pour les configurations monorepo, suivez les instructions ici.

Fenêtre de terminal
$ npx ts-node src/generate-metadata.ts
# OU npx ts-node apps/{YOUR_APP}/src/generate-metadata.ts

Maintenant, le fichier de métadonnées sérialisé doit être chargé par la méthode SwaggerModule#loadPluginMetadata, comme montré ci-dessous :

Chargement des métadonnées du plugin dans SwaggerModule
import metadata from './metadata'; // <-- fichier généré automatiquement par le "PluginMetadataGenerator"
await SwaggerModule.loadPluginMetadata(metadata); // <-- ici
const document = SwaggerModule.createDocument(app, config);

Intégration avec ts-jest (tests e2e)

Pour exécuter des tests e2e, ts-jest compile vos fichiers source à la volée, en mémoire. Cela signifie qu’il n’utilise pas le compilateur CLI de Nest et n’applique pas de plugins ni de transformations AST.

Pour activer le plugin, créez le fichier suivant dans votre répertoire de tests e2e :

Configuration du transformeur dans les tests e2e
const transformer = require('@nestjs/swagger/plugin');
module.exports.name = 'nestjs-swagger-transformer';
// vous devriez changer le numéro de version à chaque fois que vous changez la configuration ci-dessous - sinon, jest ne détectera pas les changements
module.exports.version = 1;
module.exports.factory = (cs) => {
return transformer.before(
{
// options pour @nestjs/swagger/plugin (peuvent être vides)
},
cs.program, // "cs.tsCompiler.program" pour les anciennes versions de Jest (<= v27)
);
};

Avec cela en place, importez le transformateur AST dans votre fichier de configuration jest. Par défaut (dans l’application de démarrage), le fichier de configuration des tests e2e se trouve sous le dossier test et est nommé jest-e2e.json.

Configuration jest-e2e.json
{
... // autre configuration
"globals": {
"ts-jest": {
"astTransformers": {
"before": [ "<path to the file created above>" ]
}
}
}
}

Si vous utilisez jest@^29, alors utilisez le code suivant, car l’approche précédente a été dépréciée.

Configuration pour jest@^29
{
... // autre configuration
"transform": {
"^.+\\.(t|j)s$": [
"ts-jest",
{
"astTransformers": {
"before": [ "<path to the file created above>" ]
}
}
]
}
}

Dépannage de jest (tests e2e)

Dans le cas où jest ne semble pas prendre en compte vos modifications de configuration, il est possible que Jest ait déjà mis en cache le résultat de la construction. Pour appliquer la nouvelle configuration, vous devez effacer le répertoire de cache de Jest.

Pour effacer le répertoire de cache, exécutez la commande suivante dans votre dossier de projet NestJS :

Fenêtre de terminal
$ npx jest --clearCache

Dans le cas où l’effacement automatique du cache échoue, vous pouvez toujours supprimer manuellement le dossier de cache avec les commandes suivantes :

Fenêtre de terminal
# Trouvez le répertoire de cache jest (généralement /tmp/jest_rs)
# en exécutant la commande suivante dans la racine de votre projet NestJS
$ npx jest --showConfig | grep cache
# ex résultat :
# "cache": true,
# "cacheDirectory": "/tmp/jest_rs"
# Supprimez ou videz le répertoire de cache de Jest
$ rm -rf <cacheDirectory value>
# ex :
# rm -rf /tmp/jest_rs