Skip to content
Back to archipelago.banuacoder.com

Infrastructure SDKs

network_sdk Free ​

Tier
Freeversion 2.4.4
Command
archipelago generate network_sdk
Generates
  • infrastructure/network_sdk_api
  • infrastructure/network_sdk_dio (if selected)
  • infrastructure/network_sdk_http (if selected)
Depends on
shared_app_configgenerate these first

HTTP client abstraction with Dio or http implementation.

Variables ​

VariableTypeDefaultDescription
appNamestring—The name of your application
networkLibraryenum (dio, http)dioThe HTTP client library to use
isForMonorepobooleantrueWhether this is being generated as part of a monorepo

Usage ​

Interactive ​

bash
archipelago generate network_sdk

Non-interactive (CI) ​

bash
archipelago generate network_sdk --config my_config.json

Config Template ​

json
{
  "@appName": "The name of your application",
  "appName": "MyApp",
  "@networkLibrary": "The HTTP client library to use (dio | http)",
  "networkLibrary": "dio",
  "@isForMonorepo": "Whether this is being generated as part of a monorepo",
  "isForMonorepo": true
}

Generated Structure ​

Always generated:

text
infrastructure/
└── network_sdk_api/
    ├── lib/
    │   ├── network_sdk_api.dart
    │   └── src/
    │       ├── auth/
    │       │   ├── auth_request_markers.dart
    │       │   └── auth_token_provider.dart
    │       ├── client/
    │       │   └── http_client.dart
    │       ├── di/
    │       │   └── network_injector_key.dart
    │       ├── enums/
    │       │   └── http_method.dart
    │       ├── exception/
    │       │   ├── http_cancelled_exception.dart
    │       │   ├── http_exception.dart
    │       │   ├── http_network_exception.dart
    │       │   ├── http_parse_exception.dart
    │       │   ├── http_request_exception.dart
    │       │   └── http_timeout_exception.dart
    │       ├── interceptor/
    │       │   ├── http_interceptor.dart
    │       │   └── network_interceptor_registry.dart
    │       ├── request/
    │       │   ├── http_request.dart
    │       │   └── request_options.dart
    │       └── response/
    │           └── http_response.dart
    ├── pubspec.yaml
    └── README.md

When networkLibrary is dio:

text
infrastructure/
└── network_sdk_dio/
    ├── lib/
    │   ├── network_sdk_dio.dart
    │   └── src/
    │       ├── client/
    │       │   ├── dio_http_client.dart
    │       │   └── dio_http_client_adapter.dart
    │       ├── config/
    │       │   └── dio_config.dart
    │       ├── di/
    │       │   ├── injector.dart
    │       │   ├── injector.module.dart
    │       │   └── register_module.dart
    │       ├── conversions/
    │       │   └── dio_conversions.dart
    │       └── interceptor/
    │           ├── auth_interceptor.dart
    │           └── dio_interceptor_adapter.dart
    ├── pubspec.yaml
    └── README.md

When networkLibrary is http:

text
infrastructure/
└── network_sdk_http/
    ├── lib/
    │   ├── network_sdk_http.dart
    │   └── src/
    │       ├── client/
    │       │   └── dart_http_client.dart
    │       ├── config/
    │       │   └── http_config.dart
    │       └── di/
    │           ├── injector.dart
    │           ├── injector.module.dart
    │           └── register_module.dart
    ├── pubspec.yaml
    └── README.md

Switch the HTTP client ​

A generated app wires one client: Dio or package:http. Both register as the HttpClient from network_sdk_api, so code that uses only network_sdk_api does not change when you switch. Brick 2.4.0 and later does the switch in one step. Run the brick again and pick the other networkLibrary:

bash
archipelago generate network_sdk   # answer networkLibrary: http
# or, in CI, with networkLibrary set in the config file
archipelago generate network_sdk --config network_sdk.json

The post_gen hook then does these steps:

  1. It generates infrastructure/network_sdk_http/.
  2. It removes network_sdk_dio from apps/<app>/pubspec.yaml. It also removes its import and ExternalModule(NetworkSdkDioPackageModule) from apps/<app>/lib/di/injector.dart.
  3. It adds network_sdk_http and ExternalModule(NetworkSdkHttpPackageModule).
  4. It sets infrastructure.network_library: http in archipelago.yaml. app_debugger_network reads this value.

The old package stays in infrastructure/network_sdk_dio/, because you may have changed it. The hook prints the command to delete it. Delete it only if nothing else depends on it. Then regenerate the DI code:

bash
melos bootstrap
melos run build

The switch from http to dio works the same way. If you run the brick again with the client that is already wired, nothing changes. If app_debugger_network is installed, the hook tells you to run it again, because its Network tab inspects one client only.

Code that imports package:dio or package:http directly, or that gets a Dio from GetIt, is not part of the switch. Move that code to HttpClient before you switch.

Named client keys ​

network_sdk_api exports NetworkInjectorKey — a fixed set of DI instance names (defaultClient, authClient, cdnClient, analyticsClient, plus allClientNames) intended for apps that register more than one Dio/ HttpClient (e.g. @Named(NetworkInjectorKey.authClient)). Its stated purpose is letting app_debugger_network enumerate every registered client and attach an Alice adapter to each without hardcoding names — the brick itself does not register any named client; using the keys is opt-in.

Debug inspector integration ​

NetworkInterceptorRegistry (in network_sdk_api) is the port a package that cannot see the app's client uses to hand it a vendor-native interceptor. app_debugger_network registers Alice's adapter there. DioHttpClient adopts a Dio Interceptor and DartHttpClient adopts a void Function(http.Response) observer, whether the client is built before or after the registration. Production builds register nothing.

Auth integration ​

The HTTP clients attach the app's session bearer and recover from a 401 on their own — no hand-written interceptor. The seam is one interface owned by network_sdk_api:

dart
abstract interface class AuthTokenProvider {
  Future<String?> get accessToken;
  Future<bool> onUnauthorized({required int statusCode, String? endpoint});
}

The transport depends on this port, never on auth_api, so a project can install a network SDK with no auth feature. resolveAuthTokenProvider() looks the port up in GetIt lazily, per request, and optionally: with nothing registered it answers null and every request behaves exactly as it did before the port existed.

auth_sdk >= 2.1.0 registers the implementation (AuthSessionTokenProvider) in AuthImplGlobalModule. Installing both bricks is all the wiring required.

What happens on a 401 ​

  1. AuthInterceptor (dio) / DartHttpClient (http) asks the provider to renew the session.
  2. If it answers true, the request is replayed once, re-entering the interceptor chain so it picks up the rotated bearer.
  3. If it answers false, the original failure surfaces untouched.

403 is deliberately not treated as a lapsed session — it means authenticated but not permitted, and renewing a token cannot change that. Pass renewOn: {401, 403} for backends that use 403 for expiry.

Opting a request out ​

Requests that establish or renew a session must not enter this path: a 401 from a sign-in endpoint means "wrong password", and refreshing on it would find no refresh token, fail terminally, and sign the user out. Mark them:

dart
// Dio
await dio.post<Map<String, dynamic>>(
  '/auth/login',
  data: credentials,
  options: Options(extra: AuthExemptRequest.extra),
);

// Vendor-agnostic HttpClient port
await httpClient.post('/auth/login', body: credentials,
    options: AuthExemptRequest.options);

An exempt request carries no bearer and never triggers a renewal.

Overriding the client ​

An app that registers its own Dio (or its own HttpClient) replaces the generated registration and therefore opts out of the whole lifecycle unless it passes authTokenProvider: resolveAuthTokenProvider to DioHttpClient.init / DartHttpClient — or adds AuthInterceptor itself.

Cancelling requests ​

network_sdk_api (brick >= 2.4.0) exports HttpCancelToken. Pass it in RequestOptions.cancelToken. When you call cancel(), every request that uses the token stops and throws HttpCancelledException:

When you cancelResult
Before the request startsThrows HttpCancelledException. Nothing is sent.
While the request is in flightThe transport aborts the request (dio CancelToken, http AbortableRequest). Throws HttpCancelledException.
After the request completedNothing happens.

Both clients support cancellation. A token stays cancelled, so create a new token for new work. A settled request detaches from its token, so one token can serve many requests over a long lifetime.

The usual owner is a Cubit or Bloc. It keeps one token, passes the token down to the datasource, and cancels it in close():

dart
class OrdersCubit(this._repository) extends Cubit<OrdersState> {
  this : super(const OrdersState.initial());

  final OrdersRepository _repository;
  final _cancelToken = HttpCancelToken();

  Future<void> load() async {
    emit(const OrdersState.loading());
    try {
      final orders = await _repository.fetch(cancelToken: _cancelToken);
      emit(OrdersState.loaded(orders));
    } on HttpCancelledException {
      return; // Closed while loading: nothing to show.
    } on HttpException catch (e) {
      if (!isClosed) emit(OrdersState.error(e.message));
    }
  }

  @override
  Future<void> close() {
    _cancelToken.cancel('OrdersCubit closed');
    return super.close();
  }
}

// Datasource
Future<HttpResponse> fetch({HttpCancelToken? cancelToken}) =>
    _client.get('/orders', options: RequestOptions(cancelToken: cancelToken));
  • A Cubit throws StateError when it emits after close(). Return on HttpCancelledException. After any other await, check isClosed before you emit.
  • A Bloc ignores emits from a handler after close(). Cancel the token so that the request also stops.
  • If a use case turns exceptions into a Failure, the Cubit cannot see HttpCancelledException. Check isClosed after the await instead, as LoginCubit in auth_sdk does.
  • For a Riverpod notifier, call ref.onDispose(_cancelToken.cancel). For a Provider ChangeNotifier, cancel the token in dispose().

Changelog ​

Run archipelago brick info network_sdk to see the latest published version. Enterprise customers can read the full CHANGELOG.md in the brick source repository.