jh_network_core 0.1.0
jh_network_core: ^0.1.0 copied to clipboard
A configurable, business-agnostic Dio client builder with layered overrides, response decoding, error mapping, and logging hooks.
jh_network_core #
A small, business-agnostic Dio client builder for applications that need shared network defaults with repository-level overrides.
The package focuses on client assembly rather than API definitions. It works with plain Dio, Retrofit, or any library that accepts a Dio instance.
Features #
- Dynamic base URL and request headers
- Shared configuration with repository-level overrides
- Configurable header merge precedence
- Provider-specific response decoding
- Business response validation
- Network error classification and custom messages
- Logging hooks without a logging framework dependency
- Custom Dio interceptor support
- Pure Dart implementation with no Flutter dependency
Installation #
dependencies:
jh_network_core: ^0.1.0
Basic usage #
import 'package:jh_network_core/jh_network_core.dart';
final factory = NetworkClientFactory(
NetworkClientConfig(
baseUrlProvider: () => environment.apiBaseUrl,
headersProvider: (request) async => {
'accept-language': localeProvider(),
'authorization': await tokenProvider(),
},
networkErrorMessageProvider: (kind, error) => switch (kind) {
NetworkErrorKind.noConnection => 'No internet connection.',
NetworkErrorKind.timeout => 'The request timed out.',
_ => null,
},
),
);
final dio = factory.create();
Providers are evaluated for every request, so environment, locale, and authentication changes do not require rebuilding the client.
Repository-level overrides #
Create clients with shared application defaults and local differences:
final loginDio = factory.create(
overrides: NetworkClientOverrides(
baseUrlProvider: () => environment.loginBaseUrl,
headersProvider: (_) => {'x-api-module': 'login'},
receiveTimeout: const Duration(seconds: 30),
),
);
final sportDio = factory.create(
overrides: NetworkClientOverrides(
baseUrlProvider: () => environment.sportBaseUrl,
responseDataDecoder: decodeSportResponse,
businessResponseValidator: validateSportResponse,
),
);
Configuration precedence is:
- Shared
NetworkClientConfig - Repository
NetworkClientOverrides - Per-request Dio options
Shared and repository headers are merged by key. Repository headers override shared headers. Per-request headers override the merged headers by default.
To force configured headers to override per-request values:
const NetworkClientOverrides(
headerMergePolicy: HeaderMergePolicy.commonOverridesRequest,
);
Business responses #
HTTP 200 does not always mean business success. Convert unsuccessful business responses into DioException values:
final config = NetworkClientConfig(
baseUrlProvider: () => 'https://api.example.com',
businessResponseValidator: (response) {
final data = response.data;
return data is Map<String, dynamic> && data['code'] == 0;
},
businessErrorMessageProvider: (response) {
final data = response.data;
return data is Map<String, dynamic> ? data['message'] as String? : null;
},
);
Response decoding #
Different providers can return different envelopes. Decode the response before business validation:
NetworkClientOverrides(
responseDataDecoder: (data, request) => decodeProviderEnvelope(data),
businessResponseValidator: (response) {
final envelope = response.data as ProviderEnvelope;
return envelope.success;
},
);
Retrofit #
Pass the configured Dio instance to a Retrofit-generated API:
final dio = factory.create(overrides: sportOverrides);
final api = SportApi(dio);
jh_network_core intentionally does not depend on Retrofit, state management, dependency injection, localization, or a logging framework.
Error messages #
The package classifies transport and HTTP failures as NetworkErrorKind. Applications provide user-facing messages, keeping localization outside the networking package.
Additional information #
Issues and feature requests are tracked on GitHub. Contributions are welcome through pull requests.
This package is distributed under the MIT License.