Setting Up the Network SDK
What you'll learn
- Generating the Network SDK with Dio or http backend
- Understanding the API/Impl split for HTTP clients
- Configuring interceptors, base URLs, and error handling
- Using the network client in feature datasources
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- Understanding of HTTP clients in Flutter
Step 1: Generate the Network SDK
bash
archipelago generate network_sdkYou will be prompted for:
- appName —
MyApp(must match your monorepo app name) - networkLibrary —
dio(recommended, supports interceptors) orhttp - isForMonorepo —
true
Or use a config file:
json
{
"appName": "MyApp",
"networkLibrary": "dio",
"isForMonorepo": true
}bash
archipelago generate network_sdk --config network_config.jsonStep 2: Understand the Generated Structure
The Network SDK uses the API/Impl split pattern so you can swap HTTP backends without touching feature code:
infrastructure/
├── network_sdk_api/
│ └── lib/src/
│ ├── network_client.dart # Abstract HTTP client contract
│ ├── network_request.dart # Request configuration
│ ├── network_response.dart # Typed response wrapper
│ └── network_exception.dart # Error types
└── network_sdk_impl/
└── lib/src/
├── dio_network_client.dart # Dio implementation
├── interceptors/
│ ├── auth_interceptor.dart # Token attachment
│ ├── logging_interceptor.dart
│ └── retry_interceptor.dart
└── di/
└── network_module.dart # DI registrationStep 3: Configure Base URLs
The network module registers per-flavor base URLs. Edit the DI module:
dart
// network_sdk_impl/lib/src/di/network_module.dart
void init(Flavor flavor) {
final baseUrl = switch (flavor) {
Flavor.development => 'https://api-dev.myapp.com',
Flavor.staging => 'https://api-staging.myapp.com',
Flavor.production => 'https://api.myapp.com',
};
getIt.registerSingleton<NetworkClient>(
DioNetworkClient(baseUrl: baseUrl),
);
}Step 4: Use Interceptors (Dio)
When you choose dio, the generated SDK includes pre-built interceptors:
dart
// Auth interceptor attaches tokens to every request
class AuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final token = getIt<TokenProvider>().accessToken;
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
}Add or remove interceptors in the network module:
dart
Dio()
..interceptors.addAll([
AuthInterceptor(),
LoggingInterceptor(),
RetryInterceptor(maxRetries: 3),
]);Step 5: Use in Feature Datasources
Feature datasources depend on network_sdk_api only, never on the impl:
dart
// In a feature's remote datasource
class PaymentRemoteDatasource {
final NetworkClient _client;
PaymentRemoteDatasource(this._client);
Future<List<PaymentModel>> getPayments() async {
final response = await _client.get('/payments');
return (response.data as List)
.map((e) => PaymentModel.fromJson(e))
.toList();
}
Future<PaymentModel> createPayment(CreatePaymentRequest request) async {
final response = await _client.post(
'/payments',
body: request.toJson(),
);
return PaymentModel.fromJson(response.data);
}
}Step 6: Choosing Dio vs http
| Capability | Dio | http |
|---|---|---|
| Interceptors | Built-in chain | Manual middleware |
| File upload/download | Built-in with progress | Manual implementation |
| Request cancellation | CancelToken | Manual StreamSubscription |
| Retry logic | Interceptor-based | Custom wrapper |
| Package size | Larger | Minimal |
Recommendation: Use dio for production apps with complex networking needs. Use http for lightweight apps or when minimizing dependencies.
Error Handling
The generated NetworkException provides typed errors:
dart
try {
final response = await client.get('/users');
} on NetworkException catch (e) {
switch (e) {
case UnauthorizedException():
// Redirect to login
case TimeoutException():
// Show retry UI
case ServerException(:final statusCode):
// Log to monitoring
}
}Next Steps
- Set up authentication to use token-based requests
- Add monitoring to track network failures