request<T> method

  1. @override
Future<T> request<T>({
  1. required String endpoint,
  2. required HttpMethod method,
  3. Object? body,
  4. Map<String, String>? headers,
  5. required T fromJson(
    1. Map<String, dynamic>
    ),
})
override

Performs an asynchronous network request and decodes the JSON response.

This method automatically retries failed requests up to _maxRetries times using an exponential backoff strategy.

Parameters:

  • endpoint: The API path (e.g., "/api/links").
  • method: The HttpMethod for the request.
  • body: Optional object to be sent as a JSON request body.
  • headers: Optional map of additional HTTP headers.
  • fromJson: A factory function to transform the response JSON into type T.

Throws a LinkFortyError (e.g., NetworkError, InvalidResponseError) if the request ultimately fails.

Implementation

@override
Future<T> request<T>({
  required String endpoint,
  required HttpMethod method,
  Object? body,
  Map<String, String>? headers,
  required T Function(Map<String, dynamic>) fromJson,
}) async {
  LinkFortyError? lastError;

  for (var attempt = 1; attempt <= _maxRetries; attempt++) {
    try {
      return await _performRequest<T>(
        endpoint: endpoint,
        method: method,
        body: body,
        headers: headers,
        fromJson: fromJson,
      );
    } catch (e) {
      // If it's already a LinkFortyError (from above rethrow), just rethrow it
      if (e is LinkFortyError) {
        rethrow;
      }

      // Otherwise wrap it
      lastError = NetworkError(e);

      // Exponential backoff: 1s, 2s, 4s
      if (attempt < _maxRetries) {
        final delaySeconds = math.pow(2.0, attempt - 1).toInt();
        LinkFortyLogger.log(
          'Request failed (attempt $attempt/$_maxRetries), retrying in ${delaySeconds}s... Error: $e',
        );
        await Future.delayed(Duration(seconds: delaySeconds));
      }
    }
  }

  throw lastError ??
      NetworkError(Exception('Request failed after $_maxRetries attempts'));
}