Aller au contenu principal

29-3 Documenter l'API selon le standard OpenAPI

Bien que nous puissions voir les différents points d'entrée de l'API et tester des requêtes, l'information est plutôt limitée.

Par exemple, pour l'action de création d'un projet, nous ne savons pas vraiment ce que nous devons envoyer à l'API. Quels sont les attributs d'un projet, par exemple? Quel est le type de retour?

http://localhost:4200

Définir les propriétés des DTO via @ApiProperty

Via le décorateur @ApiProperty, il est possible de définir pour chaque propriété des DTO un exemple et une description:

src/projets/dto/create-projet.dto.ts
export class CreateProjetDto {
@ApiProperty({
description: 'Le nom du projet',
example: 'LAN Party',
})
nom: string;
@ApiProperty({
description: 'la description du projet',
example: "Tout ce qui à trait à l'organisation du LAN Party",
})
description: string;
@ApiProperty({
description: "L'URL de l'image du projet",
example: 'https://i.imgur.com/Y5nZ4Qe.jpg',
})
image_url?: string;
}
attention

Par défaut, la documentation Swagger de votre DTO de création ne sera pas reconduite dans votre DTO de mise à jour (update). En effet, le PartialType importé de @nestjs/mapped-types ne transfert pas la documentation:

import { PartialType } from '@nestjs/mapped-types';
import { CreateProjetDto } from './create-projet.dto';

export class UpdateProjetDto extends PartialType(CreateProjetDto) {}

Pour que la doc soit transférée, vous devez plutôt utiliser PartialType en provenance de la librairie @nestjs/swagger:

import { PartialType } from '@nestjs/swagger';
import { CreateProjetDto } from './create-projet.dto';

export class UpdateProjetDto extends PartialType(CreateProjetDto) {}

Il est possible de sélectionner le bon import de PartialType à l'aide de WebStorm de cette façon:

img

info

Il est possible de spécifier simplement @ApiProperty, sans la description ou l'exemple, mais le tout donne plus de contexte à la documentation.

Cela ajoute automatiquement un exemple de Request Body, ainsi que la définition du schéma de données attendu:

http://localhost:4200
http://localhost:4200

Définir le type de la réponse via @ApiResponse

Afin de spécifier adéquatement le type de retour associé à une réponse d'API, on peut utiliser le décorateur @ApiResponse sur une fonction de contrôleur.

src/projets/projets.controller.ts
@ApiResponse({
type: Projet,
})
@Get(':id')
findOne(@Param('id') id: string) {
const projet = this.projetsService.obtenir(+id);

if (!projet) throw new NotFoundException();

return projet;
}

Ainsi, maintenant pour la fonction en question, le type de retour sera défini dans la section "schema" du bloc Responses.

http://localhost:4200

Le tout manque de détail cependant, pusiqu'au-delà de savoir qu'un Projet sera retourné, on ne sait pas vraiment ce que constitue un projet. Nous verrons dans la prochaine section comment ajouter plus de détails.

Il est aussi possible de donner plus de détails sur le statut de la réponse, en utilisant un décorateur plus précis, comme @ApiOkResponse plutôt que simplement ApiResponse:

src/projets/projets.controller.ts
@ApiOkResponse({
type: Projet,
})
@Get(':id')
findOne(@Param('id') id: string) {
const projet = this.projetsService.obtenir(+id);

if (!projet) throw new NotFoundException();

return projet;
}

Le code de retour 200 sera ainsi défini comme code de réponse possible.

Définir les attributs du modèle via @ApiProperty()

Le décorateur @ApiProperty() peut aussi être utilisé dans le modèle/entité pour définir les propriétés.

src/projets/entities/projet.entity.ts
import { ApiProperty } from '@nestjs/swagger';

export class Projet {
@ApiProperty()
id: number;

@ApiProperty()
nom: string;

@ApiProperty()
description: string;

@ApiProperty()
image_url?: string;

@ApiProperty()
date_creation: string;

@ApiProperty()
date_modification: string;
}

Cela nous permettant d'avoir un exemple de valeur et un schéma dans la section Responses:

http://localhost:4200
http://localhost:4200

De plus, il est possible, comme dans les DTO, de spécifier un exemple et une description pour chacun des attributs.

src/projets/entities/projet.entity.ts
import { ApiProperty } from '@nestjs/swagger';

export class Projet {
@ApiProperty({
description: "L'identifiant du projet",
example: 1,
})
id: number;

@ApiProperty({
description: 'Le nom du projet',
example: 'LAN Party',
})
nom: string;

@ApiProperty({
description: 'la description du projet',
example: "Tout ce qui à trait à l'organisation du LAN Party",
})
description: string;

@ApiProperty({
description: "L'URL de l'image du projet",
example: 'https://i.imgur.com/Y5nZ4Qe.jpg',
})
image_url?: string;

@ApiProperty()
date_creation: string;

@ApiProperty()
date_modification: string;
}

Ce qui viendra améliorer la section Responses de la page de documentation pour la requête en question.

http://localhost:4200

Définir un retour de type Array

Afin de spécifier que le retour attendu est un tableau, comme dans findAll() par exemple, on peut utiliser la formule suivante:

src/projets/projets.controller.ts
@ApiOkResponse({
type: [Projet],
})
@Get()
findAll() {
return this.projetsService.obtenirTous();
}

Statut Created (201)

Dans le cas de la fonction liée à l'action HTTP POST, le statut sera 201 (created). Il existe un décorateur, tout comme pour @ApiOkResponse, mais pour un statut 201, soit @ApiCreatedResponse.

src/projets/projets.controller.ts
@ApiCreatedResponse({
type: Projet,
})
@Post()
create(@Body() createProjetDto: CreateProjetDto) {
return this.projetsService.creer(createProjetDto);
}

Statuts pour @Patch et @Delete

En tant normal, @Patch et @Delete retournerons 200 (OK) si l'action a été un succès.

src/projets/projets.controller.ts
@ApiOkResponse({
type: Projet,
})
@Patch(':id')
update(@Param('id') id: string, @Body() updateProjetDto: UpdateProjetDto) {
const projetModif = this.projetsService.modifier(+id, updateProjetDto);

if (!projetModif) throw new NotFoundException();

return projetModif;
}

@ApiOkResponse()
@Delete(':id')
remove(@Param('id') id: string) {
const projet = this.projetsService.obtenir(+id);

if (!projet) throw new NotFoundException();

return this.projetsService.supprimer(+id);
}

Préciser que plus d'un statut de réponse est possible

Pour certaines actions, on peut retourner plusieurs statuts différents. Par exemple, pour GET /projets/:id, il se pourrait que le statut soit 404 (Not Found). Dans ce cas, plus d'un décorateur peut être ajouté à la fonction.

src/projets/projets.controller.ts
  @ApiOkResponse({
type: Projet,
})
@ApiNotFoundResponse()
@Get(':id')
findOne(@Param('id') id: string) {
const projet = this.projetsService.obtenir(+id);

if (!projet) throw new NotFoundException();

return projet;
}

Cela ajoutera un code de retour à la section Responses.

http://localhost:4200

Il aussi est possible d'ajouter une description pour clarifier la réponse.

@ApiNotFoundResponse({
description: "Le projet demandé n'existe pas",
})
http://localhost:4200

Level Up