Aller au contenu principal

🚨 Gestion des erreurs API

Documentation complète de la gestion des erreurs dans l'API Commerce Tracking.

🎯 Vue d'ensemble

L'API Commerce Tracking utilise un système de gestion d'erreurs standardisé avec des codes HTTP appropriés et des messages d'erreur détaillés pour faciliter le débogage et l'intégration.

Principes de gestion d'erreurs

  • Codes HTTP standardisés : Utilisation des codes HTTP appropriés
  • Messages d'erreur clairs : Messages explicites et actionables
  • Structure uniforme : Format de réponse cohérent
  • Corrélation des erreurs : Trace ID pour le suivi
  • Documentation complète : Toutes les erreurs documentées

📋 Format de réponse d'erreur

Structure standard

{
"success": false,
"message": "Description générale de l'erreur",
"result": null,
"errors": [
"Détail de l'erreur 1",
"Détail de l'erreur 2"
],
"except": {
"type": "ValidationError",
"code": "VALIDATION_FAILED",
"trace_id": "uuid-string",
"timestamp": "2024-01-15T10:30:00Z"
}
}

Champs de la réponse

ChampTypeDescription
successbooleanToujours false pour les erreurs
messagestringMessage d'erreur principal
resultnullToujours null pour les erreurs
errorsarrayListe détaillée des erreurs
exceptobjectInformations techniques supplémentaires

🔢 Codes d'erreur HTTP

400 - Bad Request

Cause : Données de requête invalides ou malformées.

{
"success": false,
"message": "Données de requête invalides",
"result": null,
"errors": [
"Le champ 'collection_date' est requis",
"Le format de date doit être ISO 8601 (YYYY-MM-DDTHH:mm:ssZ)",
"La quantité doit être un nombre positif"
],
"except": {
"type": "ValidationError",
"code": "INVALID_REQUEST_DATA",
"trace_id": "req_123456789",
"timestamp": "2024-01-15T10:30:00Z"
}
}

401 - Unauthorized

Cause : Authentification manquante, invalide ou expirée.

{
"success": false,
"message": "Authentification requise",
"result": null,
"errors": [
"Token JWT manquant ou invalide",
"Veuillez vous connecter pour accéder à cette ressource"
],
"except": {
"type": "AuthenticationError",
"code": "UNAUTHORIZED",
"trace_id": "req_123456790",
"timestamp": "2024-01-15T10:30:00Z"
}
}
{
"success": false,
"message": "Token expiré",
"result": null,
"errors": [
"Le token JWT a expiré",
"Veuillez vous reconnecter ou utiliser le refresh token"
],
"except": {
"type": "AuthenticationError",
"code": "TOKEN_EXPIRED",
"trace_id": "req_123456791",
"timestamp": "2024-01-15T10:30:00Z"
}
}

403 - Forbidden

Cause : Permissions insuffisantes pour accéder à la ressource.

{
"success": false,
"message": "Permissions insuffisantes",
"result": null,
"errors": [
"Votre rôle (Agent) ne vous permet pas de valider des collections",
"Seuls les Chefs d'Équipe et Superviseurs peuvent effectuer cette action"
],
"except": {
"type": "AuthorizationError",
"code": "INSUFFICIENT_PERMISSIONS",
"trace_id": "req_123456792",
"timestamp": "2024-01-15T10:30:00Z"
}
}

404 - Not Found

Cause : Ressource demandée non trouvée.

{
"success": false,
"message": "Ressource non trouvée",
"result": null,
"errors": [
"Collection avec l'ID 999 non trouvée",
"Vérifiez que l'ID est correct et que la ressource existe"
],
"except": {
"type": "ResourceNotFoundError",
"code": "RESOURCE_NOT_FOUND",
"trace_id": "req_123456793",
"timestamp": "2024-01-15T10:30:00Z"
}
}

409 - Conflict

Cause : Conflit avec l'état actuel de la ressource.

{
"success": false,
"message": "Conflit d'état",
"result": null,
"errors": [
"Impossible de modifier une collection déjà validée",
"La collection doit être en état 'draft' pour être modifiée"
],
"except": {
"type": "StateConflictError",
"code": "STATE_CONFLICT",
"trace_id": "req_123456794",
"timestamp": "2024-01-15T10:30:00Z"
}
}

422 - Unprocessable Entity

Cause : Données valides mais impossibles à traiter.

{
"success": false,
"message": "Impossible de traiter les données",
"result": null,
"errors": [
"La date de collection ne peut pas être dans le futur",
"La quantité déclarée dépasse la capacité du transport choisi"
],
"except": {
"type": "BusinessLogicError",
"code": "BUSINESS_RULE_VIOLATION",
"trace_id": "req_123456795",
"timestamp": "2024-01-15T10:30:00Z"
}
}

429 - Too Many Requests

Cause : Limite de taux dépassée.

{
"success": false,
"message": "Trop de requêtes",
"result": null,
"errors": [
"Limite de 100 requêtes par minute dépassée",
"Veuillez attendre 45 secondes avant de refaire une requête"
],
"except": {
"type": "RateLimitError",
"code": "RATE_LIMIT_EXCEEDED",
"trace_id": "req_123456796",
"timestamp": "2024-01-15T10:30:00Z",
"retry_after": 45
}
}

500 - Internal Server Error

Cause : Erreur interne du serveur.

{
"success": false,
"message": "Erreur interne du serveur",
"result": null,
"errors": [
"Une erreur inattendue s'est produite",
"Veuillez réessayer dans quelques minutes"
],
"except": {
"type": "InternalServerError",
"code": "INTERNAL_ERROR",
"trace_id": "req_123456797",
"timestamp": "2024-01-15T10:30:00Z"
}
}

503 - Service Unavailable

Cause : Service temporairement indisponible.

{
"success": false,
"message": "Service temporairement indisponible",
"result": null,
"errors": [
"Le service de validation est temporairement indisponible",
"Veuillez réessayer dans quelques minutes"
],
"except": {
"type": "ServiceUnavailableError",
"code": "SERVICE_UNAVAILABLE",
"trace_id": "req_123456798",
"timestamp": "2024-01-15T10:30:00Z"
}
}

🔍 Types d'erreurs spécialisées

Erreurs de validation

{
"success": false,
"message": "Erreur de validation des données",
"result": null,
"errors": [
"collection_date: La date est requise",
"collector_id: L'ID du collecteur doit être un nombre",
"trade_data.products[0].quantity: La quantité doit être supérieure à 0",
"trade_data.trader_info.email: Le format email est invalide"
],
"except": {
"type": "ValidationError",
"code": "VALIDATION_FAILED",
"details": {
"field_errors": {
"collection_date": ["La date est requise"],
"collector_id": ["L'ID du collecteur doit être un nombre"],
"trade_data.products[0].quantity": ["La quantité doit être supérieure à 0"],
"trade_data.trader_info.email": ["Le format email est invalide"]
}
},
"trace_id": "req_123456799",
"timestamp": "2024-01-15T10:30:00Z"
}
}

Erreurs de workflow

{
"success": false,
"message": "Transition d'état non autorisée",
"result": null,
"errors": [
"Impossible de valider une collection en état 'approved'",
"Les transitions autorisées depuis 'approved' sont: []",
"État actuel: 'approved', État demandé: 'validated'"
],
"except": {
"type": "WorkflowError",
"code": "INVALID_STATE_TRANSITION",
"details": {
"current_state": "approved",
"requested_state": "validated",
"allowed_transitions": []
},
"trace_id": "req_123456800",
"timestamp": "2024-01-15T10:30:00Z"
}
}

Erreurs de communication NATS

{
"success": false,
"message": "Service temporairement indisponible",
"result": null,
"errors": [
"Impossible de communiquer avec le service TradeFlow",
"Le service ne répond pas dans les temps impartis"
],
"except": {
"type": "CommunicationError",
"code": "NATS_SERVICE_UNAVAILABLE",
"details": {
"service": "TradeFlow Service",
"timeout": 5000,
"attempts": 3
},
"trace_id": "req_123456801",
"timestamp": "2024-01-15T10:30:00Z"
}
}

Erreurs de base de données

{
"success": false,
"message": "Erreur de base de données",
"result": null,
"errors": [
"Contrainte de clé étrangère violée",
"Le collecteur avec l'ID 999 n'existe pas"
],
"except": {
"type": "DatabaseError",
"code": "FOREIGN_KEY_CONSTRAINT",
"details": {
"constraint": "fk_collections_collector_id",
"table": "collections",
"column": "collector_id"
},
"trace_id": "req_123456802",
"timestamp": "2024-01-15T10:30:00Z"
}
}

🛠️ Gestion des erreurs côté client

JavaScript/TypeScript

class ApiError extends Error {
public status: number;
public code: string;
public traceId: string;
public errors: string[];

constructor(response: any) {
super(response.message);
this.status = response.status;
this.code = response.except?.code || 'UNKNOWN_ERROR';
this.traceId = response.except?.traceId;
this.errors = response.errors || [];
}
}

async function handleApiRequest(url: string, options: RequestInit) {
try {
const response = await fetch(url, options);
const data = await response.json();

if (!response.ok) {
throw new ApiError({ ...data, status: response.status });
}

return data;
} catch (error) {
if (error instanceof ApiError) {
// Gestion des erreurs API
console.error(`API Error ${error.code}:`, error.message);
console.error('Trace ID:', error.traceId);
console.error('Details:', error.errors);

// Actions spécifiques selon le code d'erreur
switch (error.code) {
case 'TOKEN_EXPIRED':
// Rediriger vers la page de connexion
window.location.href = '/login';
break;
case 'RATE_LIMIT_EXCEEDED':
// Afficher un message et attendre
const retryAfter = error.except?.retry_after || 60;
showMessage(`Trop de requêtes. Réessayez dans ${retryAfter} secondes.`);
break;
default:
showMessage(`Erreur: ${error.message}`);
}
} else {
// Erreur réseau ou autre
console.error('Network error:', error);
showMessage('Erreur de connexion. Vérifiez votre réseau.');
}

throw error;
}
}

Retry automatique

async function apiRequestWithRetry(
url: string,
options: RequestInit,
maxRetries = 3
): Promise<any> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await handleApiRequest(url, options);
} catch (error) {
if (error instanceof ApiError) {
// Ne pas retry pour certaines erreurs
if ([400, 401, 403, 404, 422].includes(error.status)) {
throw error;
}

// Retry pour les erreurs temporaires
if (attempt === maxRetries) {
throw error;
}

// Attendre avant de retry
const delay = Math.pow(2, attempt) * 1000; // Backoff exponentiel
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}

📊 Monitoring des erreurs

Métriques d'erreurs

// Collecte des métriques d'erreurs
const errorMetrics = {
total_errors: 0,
errors_by_code: {},
errors_by_endpoint: {},
error_rate: 0,
last_error_time: null
};

function trackError(error: ApiError, endpoint: string) {
errorMetrics.total_errors++;
errorMetrics.errors_by_code[error.code] =
(errorMetrics.errors_by_code[error.code] || 0) + 1;
errorMetrics.errors_by_endpoint[endpoint] =
(errorMetrics.errors_by_endpoint[endpoint] || 0) + 1;
errorMetrics.last_error_time = new Date().toISOString();

// Envoyer aux services de monitoring
sendToMonitoring({
type: 'api_error',
code: error.code,
status: error.status,
endpoint,
trace_id: error.traceId,
timestamp: new Date().toISOString()
});
}

🔧 Bonnes pratiques

Côté serveur

  • Messages d'erreur clairs : Messages compréhensibles par les utilisateurs
  • Codes d'erreur cohérents : Utilisation de codes standardisés
  • Trace ID : Identifiant unique pour le suivi des erreurs
  • Logging complet : Enregistrement détaillé pour le débogage
  • Validation précoce : Validation des données dès la réception

Côté client

  • Gestion gracieuse : Affichage d'erreurs utilisateur-friendly
  • Retry intelligent : Retry automatique pour les erreurs temporaires
  • Fallback : Actions de secours en cas d'erreur
  • Monitoring : Collecte des métriques d'erreurs
  • User feedback : Communication claire des erreurs à l'utilisateur

Cette documentation fournit une base solide pour la gestion des erreurs dans l'API Commerce Tracking, garantissant une expérience utilisateur optimale et facilitant le débogage.