Planned Update

This module is in the queue for a documentation refresh.

HTTP Client & Interceptors

1. Requirements Document

Overview

A comprehensive networking layer that abstracts the underlying HTTP client (Dio/Http), provides centralized interceptors for authentication and logging, and enforces a strict contract for all API interactions.

User Stories

  • As a Developer, I want to attach an Auth Token to every request automatically.
  • As a Developer, I want to log all network traffic in debug mode for easier troubleshooting.
  • As a Developer, I want to swap the HTTP client implementation without breaking feature code.

Functional Requirements

  1. Client Abstraction:
    • Unified interface (IHttpClient) supporting GET, POST, PUT, DELETE, PATCH.
  2. Interceptors:
    • AuthInterceptor: Injects Authorization: Bearer <token>.
    • RetryInterceptor: Retries failed requests with exponential backoff.
    • LoggerInterceptor: Pretty prints request/response details.
  3. Error Handling:
    • Standardized NetworkException mapping (401 -> Unauthorized, 500 -> ServerError).

2. Technical Document

Architecture

System Architecture

The HTTP Module uses the Interceptor Pattern to handle cross-cutting concerns like Authentication and Logging independently of the business logic. The `IHttpClient` interface ensures easy mocking for unit testing.

API Design

Client Interface

abstract class IHttpClient {
  Future<Result<T>> get<T>(String path, {Map<String, dynamic>? query});
  Future<Result<T>> post<T>(String path, {dynamic data});
  // ...
}

Interceptor Setup

class AuthInterceptor implements Interceptor {
  final TokenStorage storage;
 
  @override
  void onRequest(RequestOptions options) {
    final token = storage.getToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
  }
}

Usage

final client = HttpClient(
    baseUrl: 'https://api.example.com',
    interceptors: [
        AuthInterceptor(),
        LoggerInterceptor(),
    ]
);
 
final result = await client.get('/users/1');