Les controllers

routing-controllers : @JsonController, @Post, @Get, Modules

Bootcode IWA-S04 — Semaine 20, Jour 3

Objectifs de la leçon

1. Savoir lire un controller routing-controllers

Comprendre les décorateurs @JsonController, @Post, @Get, @Body, @Param

2. Identifier les endpoints et leurs méthodes HTTP

Chaque décorateur correspond à une méthode HTTP et une route

3. Comprendre le rĂ´le des middlewares (auth, rate limiter)

@UseBefore protège les routes avec AuthenticationMiddleware

4. Voir comment les use cases sont injectés dans les controllers

Le controller reçoit ses use cases par injection Inversify

Plan du cours

1

routing-controllers : des décorateurs TypeScript

Qui génèrent des routes Express automatiquement

2

Les décorateurs essentiels

@JsonController, @Post, @Get, @Body(), @Param()

3

@UseBefore — protéger les routes

AuthenticationMiddleware, rate limiter

4

Lire un vrai controller : UserController

Comprendre chaque ligne du codebase

5

Le pattern Module

La classe qui configure le DI pour le controller

routing-controllers

Express avec des décorateurs TypeScript

« Plus de app.post() manuel. Les décorateurs génèrent les routes Express pour toi. »

Avant / Après routing-controllers

❌ Express manuel

app.post('/users/signup', async (req, res) => {

const { email, password } = req.body;

const user = await signUp.execute({ email, password });

res.json(user);

});

Manuel, répétitif, pas de validation auto.

âś… routing-controllers

@JsonController('/users')

export class UserController {

@Post('/signup')

signup(@Body() body: SignUpCommand) {

return this.signUp.execute(body);

}

}

Déclaratif, validation auto, injection DI.

Les décorateurs essentiels

Chaque décorateur a un rôle précis.

@JsonController('/users')

Déclare la classe comme controller. Préfixe toutes les routes avec /users. Réponses en JSON automatiques.

@Post('/signup')

Crée une route POST /users/signup. Aussi : @Get, @Put, @Delete, @Patch.

@Body() body: SignUpCommand

Extrait et valide le body de la requête. Le type est un DTO validé par class-validator.

@Param('id') id: string

Extrait un paramètre d'URL. /users/:id → @Param('id').

class-validator — validation automatique

Les DTOs utilisent des décorateurs de validation. routing-controllers valide avant d'appeler la méthode.

export class SignUpCommand {

@IsEmail()

email: string;

@IsNotEmpty()

@MinLength(8)

password: string;

}

// Si la validation échoue → 400 Bad Error automatiquement

// La méthode du controller n'est jamais appelée

💡 Le controller ne fait AUCUNE validation manuelle. class-validator protège l'API automatiquement.

@UseBefore

Protéger les routes avec un middleware

« @UseBefore(AuthenticationMiddleware) vérifie le JWT avant d'exécuter la méthode. »

Middleware : route vs classe

Au niveau route

@Get('/me')

@UseBefore(AuthMiddleware)

me(@Req() req: Request) {

return req.user;

}

Seule cette route est protégée.

Au niveau classe

@JsonController('/admin')

@UseBefore(AuthMiddleware, AdminGuard)

export class AdminController { ... }

Toutes les routes du controller sont protégées.

UserController du codebase

Lire et comprendre chaque ligne d'un vrai controller.

@JsonController('/users')

@injectable()

export class UserController {

constructor(

@inject(TYPES.SignUpUseCase) private signUp: SignUp,

@inject(TYPES.SignInUseCase) private signIn: SignIn,

) {}

@Post('/signup')

async signup(@Body() cmd: SignUpCommand) {

return this.signUp.execute(cmd);

}

@Post('/signin')

async signin(@Body() cmd: SignInCommand) {

return this.signIn.execute(cmd);

}

}

💡 Le controller ne fait qu'orchestrer : il reçoit la commande, appelle le use case, retourne le résultat. Zéro logique métier.

Controller vs Use Case

Ne pas confondre — le controller délègue, le use case exécute.

Controller

Route HTTP. Reçoit la requête, valide, appelle le use case, formate la réponse.

Aucune logique métier.

Use Case

Logique métier. Orchestre l'agrégat, le repository, les événements.

Aucune connaissance d'HTTP.

⚠️ Piège : mettre de la logique métier dans le controller. Le controller doit rester mince.

Le pattern Module

La classe qui configure le DI pour le controller — le dernier maillon de la chaîne.

export class UserModule implements Module {

configure(container: Container) {

// Enregistrer le controller

container.bind(UserController).toSelf();

// Enregistrer les use cases qu'il utilise

container.bind(TYPES.SignUpUseCase).to(SignUp);

container.bind(TYPES.SignInUseCase).to(SignIn);

// Enregistrer les repositories

container.bind(TYPES.UserRepository).to(PostgresUserRepository);

}

}

💡 Le Module regroupe tout le câblage d'un domaine : controller + use cases + repositories. C'est le dernier maillon de la chaîne Build → Module → Controller.

Pièges courants

❌ Confondre le controller et le use case

Le controller (route HTTP) délègue. Le use case (logique métier) exécute. Ne pas mettre de métier dans le controller.

⚠️ Oublier les DTOs et la validation

Toujours utiliser un DTO avec class-validator. Sinon l'API accepte n'importe quoi.

❌ Penser que les décorateurs sont magiques

Ils génèrent du code Express standard. @Post('/signup') = app.post('/users/signup', ...).

Ă€ retenir !

✅ routing-controllers = Express avec des décorateurs TypeScript — plus de app.post() manuel.

✅ Le controller reçoit les use cases par injection (Inversify) — il ne fait qu'orchestrer.

✅ class-validator valide les DTOs automatiquement — @IsNotEmpty(), @IsEmail(), etc.

✅ Un Module configure le DI pour son controller — c'est le dernier maillon de la chaîne.

Demain : les événements asynchrones 🚀