Passer au contenu

Versioning

Le versionnement vous permet d’avoir différentes versions de vos contrôleurs ou routes individuelles fonctionnant au sein de la même application. Les applications changent très souvent et il n’est pas inhabituel qu’il y ait des modifications disruptives que vous devez apporter tout en ayant besoin de supporter la version précédente de l’application.

Il existe 4 types de versionnement qui sont pris en charge :

Type de versionnementDescription
URI VersioningLa version sera passée dans l’URI de la requête (par défaut)
Header VersioningUn en-tête de requête personnalisé spécifiera la version
Media Type VersioningL’en-tête Accept de la requête spécifiera la version
Custom VersioningTout aspect de la requête peut être utilisé pour spécifier les versions. Une fonction personnalisée est fournie pour extraire ces versions.

URI Versioning Type

Le versionnement URI utilise la version passée dans l’URI de la requête, comme https://example.com/v1/route et https://example.com/v2/route.

Pour activer le versionnement URI pour votre application, faites ceci :

main.ts
Activation du versionnement URI
const app = await NestFactory.create(AppModule);
// ou app.enableVersioning()
app.enableVersioning({
type: VersioningType.URI,
});
await app.listen(3000);

Header Versioning Type

Le versionnement par en-tête utilise un en-tête de requête personnalisé, spécifié par l’utilisateur, pour spécifier la version où la valeur de l’en-tête sera la version à utiliser pour la requête.

Exemples de requêtes HTTP pour le versionnement par en-tête :

Pour activer le Header Versioning pour votre application, faites ceci :

main.ts
Activation du versionnement par en-tête
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.HEADER,
header: 'Custom-Header',
});
await app.listen(3000);

La propriété header doit être le nom de l’en-tête qui contiendra la version de la requête.

Media Type Versioning Type

Le versionnement par type de média utilise l’en-tête Accept de la requête pour spécifier la version.

Au sein de l’en-tête Accept, la version sera séparée du type de média par un point-virgule ;. Il devrait ensuite contenir une paire clé-valeur qui représente la version à utiliser pour la requête, comme Accept: application/json;v=2. La clé est traitée plus comme un préfixe lors de la détermination de la version à configurer pour inclure la clé et le séparateur.

Pour activer le Media Type Versioning pour votre application, faites ceci :

main.ts
Activation du versionnement par type de média
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.MEDIA_TYPE,
key: 'v=',
});
await app.listen(3000);

La propriété key doit être la clé et le séparateur de la paire clé-valeur qui contient la version.

Custom Versioning Type

Le versionnement personnalisé utilise tout aspect de la requête pour spécifier la version (ou versions). La requête entrante est analysée en utilisant une fonction extractor qui retourne une chaîne ou un tableau de chaînes.

Si plusieurs versions sont fournies par le demandeur, la fonction d’extraction peut retourner un tableau de chaînes, triées par ordre de la version la plus élevée à la plus basse. Les versions sont associées à des routes par ordre de la plus élevée à la plus basse.

Si une chaîne vide ou un tableau est retourné par l’extracteur, aucune route n’est associée et un 404 est retourné.

Par exemple, si une requête entrante spécifie qu’elle prend en charge les versions 1, 2, et 3, la fonction extractor DOIT retourner [3, 2, 1]. Cela garantit que la version de route la plus élevée possible est sélectionnée en premier.

Si les versions [3, 2, 1] sont extraites, mais que seules les versions 2 et 1 existent, la route correspondant à la version 2 est sélectionnée (la version 3 est automatiquement ignorée).

Pour activer le Custom Versioning pour votre application, créez une fonction extractor et passez-la à votre application comme suit :

main.ts
Activation du versionnement personnalisé
const extractor = (request: FastifyRequest): string | string[] =>
[request.headers['custom-versioning-field'] ?? '']
.flatMap(v => v.split(','))
.filter(v => !!v)
.sort()
.reverse();
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.CUSTOM,
extractor,
});
await app.listen(3000);

Usage

Le versionnement vous permet de versionner des contrôleurs, des routes individuelles, et fournit également un moyen pour certaines ressources de renoncer au versionnement. L’utilisation du versionnement est la même quelle que soit le type de versionnement utilisé par votre application.

Controller versions

Une version peut être appliquée à un contrôleur, définissant la version pour toutes les routes au sein du contrôleur.

Pour ajouter une version à un contrôleur, procédez comme suit :

cats.controller.ts
Ajout d'une version à un contrôleur
@Controller({
version: '1',
})
export class CatsControllerV1 {
@Get('cats')
findAll(): string {
return 'Cette action retourne tous les chats pour la version 1';
}
}

Route versions

Une version peut être appliquée à une route individuelle. Cette version remplacera toute autre version qui pourrait affecter la route, comme la version du contrôleur.

Pour ajouter une version à une route individuelle, procédez comme suit :

cats.controller.ts
Ajout d'une version à une route
import { Controller, Get, Version } from '@nestjs/common';
@Controller()
export class CatsController {
@Version('1')
@Get('cats')
findAllV1(): string {
return 'Cette action retourne tous les chats pour la version 1';
}
@Version('2')
@Get('cats')
findAllV2(): string {
return 'Cette action retourne tous les chats pour la version 2';
}
}

Multiple versions

Plusieurs versions peuvent être appliquées à un contrôleur ou une route. Pour utiliser plusieurs versions, vous devez définir la version comme un tableau.

Pour ajouter plusieurs versions, procédez comme suit :

cats.controller.ts
Ajout de plusieurs versions à un contrôleur
@Controller({
version: ['1', '2'],
})
export class CatsController {
@Get('cats')
findAll(): string {
return 'Cette action retourne tous les chats pour la version 1 ou 2';
}
}

Version “Neutral”

Certaines contrôleurs ou routes peuvent ne pas se soucier de la version et auraient la même fonctionnalité indépendamment de la version. Pour cela, la version peut être définie sur le symbole VERSION_NEUTRAL.

Une requête entrante sera mappée à un contrôleur ou une route VERSION_NEUTRAL peu importe la version envoyée dans la requête en plus du fait que si la requête ne contient pas de version.

Pour ajouter un contrôleur ou une route neutre en version, procédez comme suit :

cats.controller.ts
Ajout d'un contrôleur neutre en version
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
@Controller({
version: VERSION_NEUTRAL,
})
export class CatsController {
@Get('cats')
findAll(): string {
return 'Cette action retourne tous les chats indépendamment de la version';
}
}

Global default version

Si vous ne souhaitez pas fournir de version pour chaque contrôleur ou chaque route individuelle, ou si vous souhaitez avoir une version spécifique définie comme version par défaut pour chaque contrôleur/route qui n’a pas de version spécifiée, vous pouvez définir la defaultVersion comme suit :

main.ts
Définir la version par défaut
app.enableVersioning({
// ...
defaultVersion: '1',
// ou
defaultVersion: ['1', '2'],
// ou
defaultVersion: VERSION_NEUTRAL,
});

Middleware versioning

Les middlewares peuvent également utiliser des métadonnées de versionnement pour configurer le middleware pour une version de route spécifique. Pour ce faire, fournissez le numéro de version comme l’un des paramètres de la méthode MiddlewareConsumer.forRoutes() :

app.module.ts
Utilisation du versionnement avec des middlewares
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
import { CatsController } from './cats/cats.controller';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET, version: '2' });
}
}

Avec le code ci-dessus, le LoggerMiddleware ne sera appliqué qu’à la version ‘2’ du point de terminaison /cats.