Passer au contenu

Types et paramètres

Le SwaggerModule recherche tous les decorateurs @Body(), @Query() et @Param() dans les gestionnaires de routes pour générer le document API. Il crée également des définitions de modèles correspondantes en tirant parti de la réflexion. Considérez le code suivant :

Créer un chat
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}

Basé sur le CreateCatDto, la définition de modèle suivante sera créée pour Swagger UI :

Swagger DTO

Comme vous pouvez le voir, la définition est vide bien que la classe ait quelques propriétés déclarées. Pour rendre les propriétés de la classe visibles pour le SwaggerModule, nous devons soit les annoter avec le décorateur @ApiProperty(), soit utiliser le plugin CLI (en savoir plus dans la section Plugin) qui le fera automatiquement :

Créer un DTO de chat
import { ApiProperty } from '@nestjs/swagger';
export class CreateCatDto {
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}

Ouvrons le navigateur et vérifions le modèle CreateCatDto généré :

Swagger DTO 2

De plus, le décorateur @ApiProperty() permet de définir diverses propriétés de l’objet de schéma :

Définition de propriété
@ApiProperty({
description: 'L\'âge d\'un chat',
minimum: 1,
default: 1,
})
age: number;

Pour définir explicitement le type de la propriété, utilisez la clé type :

Type de propriété
@ApiProperty({
type: Number,
})
age: number;

Tableaux

Lorsque la propriété est un tableau, nous devons indiquer manuellement le type du tableau comme indiqué ci-dessous :

Type tableau
@ApiProperty({ type: [String] })
names: string[];

Vous pouvez inclure soit le type comme le premier élément d’un tableau (comme indiqué ci-dessus), soit définir la propriété isArray sur true.

Dépendances circulaires

Lorsqu’il y a des dépendances circulaires entre les classes, utilisez une fonction paresseuse pour fournir au SwaggerModule des informations de type :

Dépendances circulaires
@ApiProperty({ type: () => Node })
node: Node;

Généralités et interfaces

Comme TypeScript ne stocke pas les métadonnées sur les génériques ou les interfaces, lorsque vous les utilisez dans vos DTO, le SwaggerModule peut ne pas être en mesure de générer correctement les définitions de modèle au moment de l’exécution. Par exemple, le code suivant ne sera pas correctement inspecté par le module Swagger :

Utilisation des génériques
createBulk(@Body() usersDto: CreateUserDto[]) {}

Pour surmonter cette limitation, vous pouvez définir le type explicitement :

Définition explicite du type
@ApiBody({ type: [CreateUserDto] })
createBulk(@Body() usersDto: CreateUserDto[]) {}

Enums

Pour identifier un enum, nous devons définir manuellement la propriété enum sur le @ApiProperty avec un tableau de valeurs :

Définition d'un enum
@ApiProperty({ enum: ['Admin', 'Moderator', 'User'] })
role: UserRole;

Alternativement, définissez un véritable enum TypeScript comme suit :

Enum TypeScript
export enum UserRole {
Admin = 'Admin',
Moderator = 'Moderator',
User = 'User',
}

Vous pouvez ensuite utiliser l’enum directement avec le décorateur de paramètre @Query() en combinaison avec le décorateur @ApiQuery() :

Filtrer par rôle
@ApiQuery({ name: 'role', enum: UserRole })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {}

Mayor query

Avec isArray défini sur true, l’enum peut être sélectionné comme un multi-sélect :

Mayor query array

Schéma d’énumérations

Par défaut, la propriété enum ajoutera une définition brute d’Enum sur le parameter.

Définition d'un enum
- breed:
type: 'string'
enum:
- Persian
- Tabby
- Siamese

La spécification ci-dessus fonctionne bien dans la plupart des cas. Cependant, si vous utilisez un outil qui prend la spécification comme entrée et génère du code côté client, vous pouvez rencontrer un problème avec le code généré contenant des enums dupliqués. Considérez le code suivant :

Code côté client généré
export class CatDetail {
breed: CatDetailEnum;
}
export class CatInformation {
breed: CatInformationEnum;
}
export enum CatDetailEnum {
Persian = 'Persian',
Tabby = 'Tabby',
Siamese = 'Siamese',
}
export enum CatInformationEnum {
Persian = 'Persian',
Tabby = 'Tabby',
Siamese = 'Siamese',
}

Vous pouvez voir que vous avez maintenant deux enums qui sont exactement les mêmes. Pour résoudre ce problème, vous pouvez passer un enumName avec la propriété enum dans votre décorateur.

Résolution du problème d'enum
export class CatDetail {
@ApiProperty({ enum: CatBreed, enumName: 'CatBreed' })
breed: CatBreed;
}

La propriété enumName permet à @nestjs/swagger de transformer CatBreed en son propre schéma, ce qui rend l’enum CatBreed réutilisable. La spécification ressemblera à ceci :

Référence à l'enum
CatDetail:
type: 'object'
properties:
...
- breed:
schema:
$ref: '#/components/schemas/CatBreed'
CatBreed:
type: string
enum:
- Persian
- Tabby
- Siamese

Définitions brutes

Dans certains scénarios spécifiques (par exemple, des tableaux profondément imbriqués, des matrices), vous pouvez vouloir décrire votre type manuellement.

Définitions brutes
@ApiProperty({
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
})
coords: number[][];

De même, pour définir votre contenu d’entrée/sortie manuellement dans les classes de contrôleur, utilisez la propriété schema :

Schematisation de l'entrée/sortie
@ApiBody({
schema: {
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
},
})
async create(@Body() coords: number[][]) {}

Modèles supplémentaires

Pour définir des modèles supplémentaires qui ne sont pas directement référencés dans vos contrôleurs mais qui doivent être inspectés par le module Swagger, utilisez le décorateur @ApiExtraModels() :

Définir un modèle supplémentaire
@ApiExtraModels(ExtraModel)
export class CreateCatDto {}

Alternativement, vous pouvez passer un objet d’options avec la propriété extraModels spécifiée au méthode SwaggerModule#createDocument(), comme suit :

Passer des modèles supplémentaires
const document = SwaggerModule.createDocument(app, options, {
extraModels: [ExtraModel],
});

Pour obtenir une référence ($ref) à votre modèle, utilisez la fonction getSchemaPath(ExtraModel) :

Obtenir le chemin du schéma
'application/vnd.api+json':
schema:
$ref: getSchemaPath(ExtraModel)

oneOf, anyOf, allOf

Pour combiner des schémas, vous pouvez utiliser les mots-clés oneOf, anyOf ou allOf (en savoir plus).

Combinaison de schémas
@ApiProperty({
oneOf: [
{ $ref: getSchemaPath(Cat) },
{ $ref: getSchemaPath(Dog) },
],
})
pet: Cat | Dog;

Si vous souhaitez définir un tableau polymorphe (c’est-à-dire un tableau dont les membres s’étendent sur plusieurs schémas), vous devez utiliser une définition brute (voir ci-dessus) pour définir votre type manuellement.

Tableau polymorphe
type Pet = Cat | Dog;
@ApiProperty({
type: 'array',
items: {
oneOf: [
{ $ref: getSchemaPath(Cat) },
{ $ref: getSchemaPath(Dog) },
],
},
})
pets: Pet[];

Les deux Cat et Dog doivent être définis comme modèles supplémentaires en utilisant le décorateur @ApiExtraModels() (au niveau de la classe).