Architecture Clean avec Node.js et TypeScript
Apprenez à structurer vos APIs Node.js avec une architecture clean, séparation des responsabilités et tests automatisés.
Architecture Clean : Guide pratique avec Node.js
L'architecture clean (Clean Architecture) est un principe de conception qui vise à créer des systèmes maintenables, testables et indépendants des frameworks.
Principes fondamentaux
Séparation des responsabilités
L'architecture clean organise le code en couches concentriques :
1. **Entités** : Logique métier pure
2. **Use Cases** : Logique applicative
3. **Interface Adapters** : Controllers, Presenters
4. **Frameworks & Drivers** : Base de données, Web
Structure du projet
src/
├── domain/
│ ├── entities/
│ ├── repositories/
│ └── use-cases/
├── infrastructure/
│ ├── database/
│ ├── web/
│ └── external/
└── application/
├── controllers/
├── presenters/
└── middleware/
Implémentation pratique
Entités métier
// domain/entities/User.ts
export class User {
constructor(
public readonly id: string,
public readonly email: string,
public readonly name: string,
private readonly passwordHash: string
) {}
public changeEmail(newEmail: string): User {
if (!this.isValidEmail(newEmail)) {
throw new Error('Invalid email format');
}
return new User(this.id, newEmail, this.name, this.passwordHash);
}
private isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
Use Cases
// domain/use-cases/CreateUser.ts
import { User } from '../entities/User';
import { UserRepository } from '../repositories/UserRepository';
import { PasswordHasher } from '../services/PasswordHasher';
export class CreateUser {
constructor(
private userRepository: UserRepository,
private passwordHasher: PasswordHasher
) {}
async execute(userData: {
email: string;
name: string;
password: string;
}): Promise<User> {
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new Error('User already exists');
}
const passwordHash = await this.passwordHasher.hash(userData.password);
const user = new User(
this.generateId(),
userData.email,
userData.name,
passwordHash
);
return this.userRepository.save(user);
}
private generateId(): string {
return Math.random().toString(36).substr(2, 9);
}
}
Tests et qualité
Cette architecture facilite grandement les tests :
// __tests__/CreateUser.test.ts
import { CreateUser } from '../src/domain/use-cases/CreateUser';
import { MockUserRepository } from './mocks/MockUserRepository';
import { MockPasswordHasher } from './mocks/MockPasswordHasher';
describe('CreateUser', () => {
let createUser: CreateUser;
let mockUserRepository: MockUserRepository;
let mockPasswordHasher: MockPasswordHasher;
beforeEach(() => {
mockUserRepository = new MockUserRepository();
mockPasswordHasher = new MockPasswordHasher();
createUser = new CreateUser(mockUserRepository, mockPasswordHasher);
});
it('should create a new user', async () => {
const userData = {
email: 'test@example.com',
name: 'Test User',
password: 'password123'
};
const user = await createUser.execute(userData);
expect(user.email).toBe(userData.email);
expect(user.name).toBe(userData.name);
});
});
Avantages de cette approche
- **Testabilité** : Chaque couche peut être testée indépendamment
- **Maintenabilité** : Code organisé et prévisible
- **Flexibilité** : Changement de framework facilité
- **Réutilisabilité** : Logique métier indépendante
Cette architecture représente un investissement initial, mais les bénéfices à long terme sont considérables.
Tags
Partager cet article
Articles similaires
Déployer en production avec Docker et GitHub Actions
Guide complet pour automatiser vos déploiements avec Docker, GitHub Actions et les bonnes pratiques de sécurité.
Guide complet des prompts pour développeurs
Découvrez les meilleures techniques de prompting pour optimiser vos interactions avec l'IA et accélérer votre développement.
React Server Components : Guide pratique
Maîtrisez les React Server Components avec des exemples concrets et des patterns d'implémentation pour vos applications Next.js.