Aller au contenu principal

Gestion des erreurs

Cette bibliothèque mappe les erreurs de l'API Mastodon vers une hiérarchie de classes scellées (sealed classes) dont la racine est MastodonException.

Hiérarchie des exceptions​

MastodonException (sealed)
├── MastodonApiException // General HTTP response errors
│ ├── MastodonUnauthorizedException // 401 - Authentication error
│ ├── MastodonForbiddenException // 403 - Permission error
│ ├── MastodonNotFoundException // 404 - Resource not found
│ ├── MastodonRateLimitException // 429 - Rate limited
│ │ ├── retryAfter // Recommended wait duration
│ │ ├── limit // Request limit for the window
│ │ ├── remaining // Remaining requests
│ │ └── resetAt // Time when the window resets
│ ├── MastodonValidationException // 422 - Validation error
│ │ ├── serverMessage // Detailed server message
│ │ ├── details // Field errors by request field
│ │ └── MastodonAlreadyVotedException // Already voted
│ └── MastodonServerException // 5xx - Server error
├── MastodonNetworkException // Network connection error
└── MastodonAuthException (sealed) // OAuth authentication flow errors
├── MastodonAuthCancelledException // User cancelled
├── MastodonAuthStateMismatchException // CSRF detected
└── MastodonAuthTokenException // Token acquisition failed

Modèles de capture de base​

Capturer toutes les erreurs​

try {
final status = await client.statuses.fetch(id);
} on MastodonException catch (e) {
print('Error: $e');
}

Gérer par code de statut HTTP​

try {
final account = await client.accounts.fetchById(accountId);
} on MastodonNotFoundException {
print('Account not found');
} on MastodonUnauthorizedException {
print('Token is invalid. Please re-authenticate');
} on MastodonRateLimitException catch (e) {
print('Rate limited. Retry after ${e.retryAfter}');
} on MastodonApiException catch (e) {
print('API error (${e.statusCode}): ${e.message}');
} on MastodonNetworkException {
print('Check your network connection');
}

Obtenir les détails des erreurs de validation​

try {
await client.accounts.create(request);
} on MastodonValidationException catch (e) {
print('Validation error: ${e.serverMessage}');
final details = e.details;
if (details != null) {
for (final entry in details.entries) {
for (final detail in entry.value) {
print('${entry.key}: ${detail.code} - ${detail.description ?? ''}');
}
}
}
}

details est indexé par champ de requête. Chaque MastodonValidationErrorDetail contient le code d'erreur du serveur et une description facultative. Les codes inconnus sont conservés sous forme de chaînes. details vaut null lorsqu'un endpoint ne renvoie pas le format de détails de validation reconnu de Mastodon.

Exceptions spéciales​

MastodonAlreadyVotedException​

Levée lorsqu'on tente de voter dans un sondage auquel on a déjà participé.

try {
await client.polls.vote(pollId, [0]);
} on MastodonAlreadyVotedException {
print('Already voted on this poll');
}

Gérer les limites de débit​

MastodonRateLimitException expose les en-têtes X-RateLimit-* de Mastodon. L'attente recommandée utilise Retry-After lorsqu'il est fourni par le serveur ou le proxy, puis se rabat sur l'horodatage X-RateLimit-Reset.

Future<T> withRetry<T>(Future<T> Function() action) async {
try {
return await action();
} on MastodonRateLimitException catch (e) {
print('${e.remaining}/${e.limit} requêtes restantes ; réinitialisation à ${e.resetAt}');
final wait = e.retryAfter ?? const Duration(seconds: 60);
await Future<void>.delayed(wait);
return action();
}
}

// Usage
final timeline = await withRetry(
() => client.timelines.fetchHome(limit: 20),
);