Documentation Index
Fetch the complete documentation index at: https://docs.chataigne.ai/llms.txt
Use this file to discover all available pages before exploring further.
Les adapters sont responsables de la transformation des données entre différentes couches de l’application. Ils permettent de maintenir une séparation claire entre le domaine et les couches externes (API, persistance, services tiers).
Problèmes Critiques
1. Gestion des Valeurs Nulles et Undefined
Le problème le plus courant avec les adapters est la gestion des valeurs nulles ou undefined. Voici comment le gérer correctement :
// ❌ À ÉVITER - Problèmes courants
class OrderAdapter {
static dtoToOrderEntity(dto: OrderDTO): Order {
// Problème 1: Pas de vérification de dto
return new Order({
id: dto.id,
customer: DtoCustomerAdapter.dtoToCustomerEntity(dto.customer), // Erreur si dto.customer est undefined
items: dto.items.map((item) => DtoItemAdapter.dtoToItemEntity(item)), // Erreur si dto.items est undefined
});
}
}
// ✅ SOLUTION CORRECTE
class OrderAdapter {
static dtoToOrderEntity(dto: OrderDTO): Order {
if (!dto) {
throw new AdapterError("DTO de commande invalide");
}
return new Order({
id: dto.id,
// Gestion sécurisée des relations
customer: dto.customer
? DtoCustomerAdapter.dtoToCustomerEntity(dto.customer)
: undefined,
// Gestion sécurisée des collections
items: (dto.items ?? []).map((item) => {
if (!item) {
throw new AdapterError("Item de commande invalide");
}
return DtoItemAdapter.dtoToItemEntity(item);
}),
});
}
}
2. Gestion des Erreurs
La gestion des erreurs dans les adapters doit être précise et informative. Voici l’approche recommandée :
// Définition de l'erreur d'adapter dans la couche infrastructure
class AdapterError extends Error {
constructor(
message: string,
public readonly field?: string,
public readonly value?: any
) {
super(message);
this.name = "AdapterError";
}
}
// Utilisation dans un adapter
class OrderAdapter {
static dtoToOrderEntity(dto: OrderDTO): Order {
try {
if (!dto) {
throw new AdapterError("DTO de commande invalide");
}
// Transformation avec validation
return new Order({
id: dto.id,
items: this.mapItems(dto.items),
customer: this.mapCustomer(dto.customer),
});
} catch (error) {
// Si c'est déjà une AdapterError, on la relance
if (error instanceof AdapterError) {
throw error;
}
// Sinon, on l'enveloppe avec plus de contexte
throw new AdapterError(
`Erreur lors de la transformation de la commande: ${error.message}`
);
}
}
private static mapItems(items: any[]): OrderItem[] {
if (!Array.isArray(items)) {
throw new AdapterError(
"Les items doivent être un tableau",
"items",
items
);
}
return items.map((item, index) => {
if (!item) {
throw new AdapterError(
`Item invalide à l'index ${index}`,
`items[${index}]`,
item
);
}
return DtoItemAdapter.dtoToItemEntity(item);
});
}
private static mapCustomer(customer: any): Customer | undefined {
if (!customer) {
return undefined;
}
return DtoCustomerAdapter.dtoToCustomerEntity(customer);
}
}
Bonnes Pratiques
1. Validation des Données
- Vérifier immédiatement les données nulles
- Utiliser l’opérateur
?? pour les valeurs par défaut
- Gérer sécuritairement les relations et collections
2. Gestion des Erreurs
- Utiliser des messages d’erreur précis
- Inclure le contexte (champ, valeur) dans les erreurs
- Valider les données avant la transformation
- Gérer les erreurs à chaque niveau de transformation
- Transformer les données étape par étape
- Utiliser des méthodes privées pour la réutilisation
- Valider à chaque étape
- Gérer séparément les relations et collections
Exemple Complet
class OrderAdapter {
static dtoToOrderEntity(dto: OrderDTO): Order {
try {
if (!dto) {
throw new AdapterError("DTO de commande invalide");
}
return new Order({
id: dto.id,
status: dto.status ?? "new",
items: this.mapItems(dto.items),
customer: this.mapCustomer(dto.customer),
delivery: this.mapDelivery(dto.delivery),
});
} catch (error) {
if (error instanceof AdapterError) {
throw error;
}
throw new AdapterError(
`Erreur lors de la transformation de la commande: ${error.message}`