WO Http
Opinionated HTTP toolkit for Flutter/Dart with:
- unified request/response models
- interceptor pipeline (
onRequest,onResponse,onError) - built-in retry interceptor
- optional auth refresh interceptor
- typed success/failure result wrappers
- multi-client factory support
- MIT licensed
Installation
From pub.dev:
dependencies:
wo_http: ^0.1.0
Or local path:
dependencies:
wo_http:
path: packages/wo_http
Then run:
flutter pub get
Import
import 'package:wo_http/wo_http.dart';
Quick Start
final client = WoDefaultHttpApiClient(
baseUrl: 'https://api.example.com',
interceptors: [
WoDefaultRetryHttpInterceptor(maxRetries: 2),
],
);
final result = await client.get<Map<String, dynamic>>('/users/42');
if (result.isSuccess) {
final user = result.data;
} else {
final message = result.failure?.message;
final type = result.failure?.errorType;
}
Request Methods
WoHttpClient exposes:
get(path, {headers, parser, errorAdapter})post(path, {data, headers, parser, errorAdapter})put(path, {data, headers, parser, errorAdapter})patch(path, {data, headers, parser, errorAdapter})delete(path, {data, headers, parser, errorAdapter})upload(path, {method, fileFieldName, fields, files, headers, parser, errorAdapter})
Typed Parser Example
class User {
final String id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) => User(
id: json['id'] as String,
name: json['name'] as String,
);
}
final result = await client.get<User>(
'/users/42',
parser: (raw) => User.fromJson(raw as Map<String, dynamic>),
);
Upload Example
final upload = await client.upload<Map<String, dynamic>>(
'/files/upload',
fileFieldName: 'file',
fields: {'folder': 'avatars'},
files: [
WoUploadFile(
bytes: <int>[/* file bytes */],
filename: 'profile.jpg',
contentType: 'image/jpeg',
),
],
);
WoUploadFile supports either bytes or path.
Error Adapter Example
WoDefaultHttpErrorAdapter is used by default. You can override it globally or per request.
class MyErrorAdapter implements WoHttpErrorAdapter {
const MyErrorAdapter();
@override
String? adaptError(dynamic error) {
if (error is Map<String, dynamic> && error['detail'] is String) {
return error['detail'] as String;
}
return 'Unexpected error';
}
}
final client = WoDefaultHttpApiClient(
baseUrl: 'https://api.example.com',
errorAdapter: const MyErrorAdapter(),
);
Auth Refresh Example
class MyAuthStrategy extends WoAuthStrategy {
const MyAuthStrategy() : super._();
@override
Future<String?> readAccessToken() async => 'access-token';
@override
Future<String?> refreshAccessToken() async => 'new-access-token';
}
final client = WoDefaultHttpApiClient(
baseUrl: 'https://api.example.com',
interceptors: [
WoDefaultAuthInterceptor(
authStrategy: const MyAuthStrategy(),
excludedExactPaths: {'/auth/login', '/auth/refresh'},
excludedPathPrefixes: {'/public/'},
),
WoDefaultRetryHttpInterceptor(maxRetries: 2),
],
);
On 401, the auth interceptor refreshes once and retries the request.
Multi-Client Setup
Use WoDataClientFactory when your app talks to multiple backends.
final factory = WoDataClientFactory.fromDefinitions([
WoDataClientDefinition(
name: 'core',
baseUrl: 'https://api.example.com',
enableLogging: true,
maxRetries: 2,
requestTimeout: const Duration(seconds: 30),
),
WoDataClientDefinition(
name: 'ai',
baseUrl: 'https://ai.example.com',
enableLogging: true,
maxRetries: 1,
requestTimeout: const Duration(seconds: 15),
),
]);
final coreClient = factory.client('core');
final aiClient = factory.client('ai');
When enableLogging is true, factory-created clients include debug logging automatically.
Registry Utility
final registry = WoDataRegistry();
registry.register<WoHttpClient>(client);
if (registry.isRegistered<WoHttpClient>()) {
final resolved = registry.resolve<WoHttpClient>();
}
Public Contracts
WoHttpClient: consumer-facing HTTP operations.WoHttpInterceptor: request/response/error hooks.WoHttpErrorAdapter: maps raw error body toString?.WoLogger: logging abstraction.
Public Models
WoHttpRequest: normalized request passed through interceptors.WoHttpResponse: normalized response witherrorType.WoResult<T>: success/failure wrapper returned by client methods.WoDataFailure: failure payload (message,errorType,cause).WoUploadFile: upload source (bytesorpath) plus metadata.WoAuthStrategy: token read/refresh contract for auth interceptor.
Enums
WoHttpMethod:get,post,put,patch,delete.WoHttpErrorType:network,timeout,unauthorized,forbidden,notFound,server,unknown.
Notes
- Retry behavior is status-code-based in
WoDefaultRetryHttpInterceptor. - Factory logging is active in debug mode (
kDebugMode) only.
Author
Amanuel.T (emantggw)