π HTTP Client¶
The project uses Dio as the primary HTTP client for all API interactions. It is wrapped and initialized through a custom HttpClient
class for consistent configuration and centralized request handling.
π File: lib/_core/http_client.dart
¶
class HttpClient {
static Future<void> init() async {
Dio dio = Dio(BaseOptions(baseUrl: Constants.apiBaseUrl));
...
di.registerLazySingleton(() => dio);
}
}
This class configures and registers Dio with necessary interceptors and a base URL, and integrates it into the appβs dependency injection container (di).
π§ Initialization¶
The HttpClient.init() method is called in bootstrap.dart during app startup.
It does the following:
- Sets a base URL from Constants.apiBaseUrl
- Adds interceptors for:
- Automatically attaching authorization tokens
- Logging requests
- Handling response and error logic
- Registers Dio in DI so it can be used anywhere in the app via di
()
π‘οΈ Interceptors¶
π Request Interceptor¶
Automatically attaches the bearer token from Hive storage (if present):
final tokenBox = await Hive.openLazyBox(Constants.tokenBoxName);
final token = await tokenBox.get(Constants.cachedTokenRef);
options.headers['authorization'] = "Bearer $token";
debugPrint("request: ${options.uri}");
β Response Interceptor¶
Only passes successful responses (status code 2xx). Others are converted to a ServerException (placeholder for now):
if (response.statusCode! >= 200 || response.statusCode! < 300) {
return handler.next(response);
} else {
response = ServerException() as Response;
return handler.next(response);
}
β Error Interceptor¶
Logs the error and continues the chain:
print('onError: => $e');
π§βπ» Accessing Dio Anywhere¶
Because Dio is registered in the DI container, you can retrieve it from anywhere using:
final dio = di<Dio>();
βΈ»
π¦ Related Files¶
File | Purpose |
---|---|
constants.dart | Stores the base URL and Hive box/token keys |
di.dart | Registers Dio as a lazy singleton |
bootstrap.dart | Calls HttpClient.init() during app startup |
error/exceptions.dart | Contains custom exception classes like ServerException |
π§ͺ Testing Tips¶
- You can replace the real Dio instance in tests with a mock:
di.unregister<Dio>(); di.registerLazySingleton<Dio>(() => MockDio());
π§ Improvements To Consider
- Use pretty_dio_logger for better request/response logs during development.