import 'dart:convert'; import 'package:http/http.dart' as http; import 'intra_api_exception.dart'; /// GET API 42 avec gestion 401 / 429 (retry + backoff). Future intraApiGet( Uri uri, { required Map headers, int maxAttempts = 4, }) async { for (var attempt = 0; attempt < maxAttempts; attempt++) { final response = await http.get(uri, headers: headers); if (response.statusCode == 429) { if (attempt + 1 >= maxAttempts) { throw const IntraRateLimitException(); } await Future.delayed(_retryDelay(response, attempt)); continue; } return response; } throw const IntraRateLimitException(); } Duration _retryDelay(http.Response response, int attempt) { final header = response.headers['retry-after']; if (header != null) { final seconds = int.tryParse(header.trim()); if (seconds != null && seconds > 0) { return Duration(seconds: seconds.clamp(1, 30)); } } // 0.8s, 1.6s, 3.2s… final ms = 800 * (1 << attempt); return Duration(milliseconds: ms.clamp(800, 8000)); } void ensureIntraOk(http.Response response) { if (response.statusCode == 401) { throw const IntraUnauthorizedException(); } if (response.statusCode == 403) { throw const IntraForbiddenException(); } if (response.statusCode == 429) { throw const IntraRateLimitException(); } if (response.statusCode != 200) { throw IntraApiErrorException( 'Erreur API (${response.statusCode})', ); } } dynamic decodeIntraBody(http.Response response) { ensureIntraOk(response); return jsonDecode(response.body); }