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.