api_network_kit 1.2.0 copy "api_network_kit: ^1.2.0" to clipboard
api_network_kit: ^1.2.0 copied to clipboard

A batteries-included, no-codegen Dio wrapper for Flutter/Dart featuring typed parsing, resilient retry, automatic token refresh, caching, pagination, and WASM-ready checks.

api_network_kit #

A batteries-included, no-codegen Dio wrapper for Flutter and Dart. It adds typed response parsing, resilient retry, automatic token refresh, persistent / ETag-aware caching, pluggable pagination, and Web/WASM-ready connectivity checks on top of Dio — with first-class testability.

Why api_network_kit? #

The runtime-wrapper segment wins on developer experience, not breadth. This package is positioned against raw Dio (which lacks the opinionated layer) and against retrofit/chopper (which demand code-generation and build_runner).

Differentiators #

  1. Zero code-generation — works instantly, no build_runner.
  2. Automatic 401 token-refresh-and-retry out of the box.
  3. Persistent + ETag-aware caching that survives restarts (via the CacheStore interface).
  4. Typed exceptions that preserve server error bodies — 422 field-validation errors are reachable.
  5. Pluggable pagination for any API shape (offset or cursor based).
  6. Web/WASM-ready with optional, pluggable connectivity checks.

Features #

  • Generic Response Parsing — automatic JSON parsing to your models, including JSON-encoded String bodies.
  • Comprehensive Error Handling — typed exceptions for all HTTP status codes that preserve the server response body (data, errors, statusCode).
  • Automatic Retry — configurable retry with exponential backoff for transient errors.
  • Automatic Token Refresh — inject a TokenRefresher to refresh expired tokens and retry the original request once on 401.
  • Connectivity Verification — pluggable ConnectivityChecker with a no-op default for pure-Dart / Web / WASM.
  • Injectable Logging — instance-based ApiLogger, silencable per-client.
  • Token Management — dynamic authorization header update and removal.
  • Pluggable PaginationOffsetPaginationStrategy and CursorPaginationStrategy with configurable field keys.
  • Response CachingCacheStore interface with in-memory ApiCache (TTL + ETag), plus request deduplication for concurrent identical GETs.
  • Flexible Interceptors — dynamic hooks for request, response, and error modification.
  • File Upload/Download — simple methods with progress callbacks.

Installation #

Add this dependency to your project's pubspec.yaml:

dependencies:
  api_network_kit: ^1.1.0

Then run:

flutter pub get

Quick Start #

Basic Setup #

import 'package:api_network_kit/api_network_kit.dart';

final api = ApiKit(baseUrl: 'https://api.example.com');

GET Request with Automatic Parsing #

class User {
  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) => User(
    id: json['id'] as int,
    name: json['name'] as String,
    email: json['email'] as String,
  );

  final int id;
  final String name;
  final String email;
}

final user = await api.get<User>(
  '/users/1',
  parser: User.fromJson,
);

Error Handling with Server Error Bodies #

try {
  final user = await api.get<User>('/users/1', parser: User.fromJson);
} on UnauthorizedException {
  print('Please log in again.');
} on UnprocessableEntityException catch (e) {
  // Field-level validation errors are now reachable:
  print(e.errors); // e.g. {'email': ['Already taken']}
} on NoInternetException {
  print('Please check your internet connection.');
} on Exception catch (e) {
  print('An error occurred: $e');
}

Advanced Configurations #

Automatic Token Refresh & Retry #

final api = ApiKit(
  baseUrl: 'https://api.example.com',
  token: initialToken,
  tokenRefresher: (error, options) async {
    // Call your refresh endpoint and return the new token.
    final newToken = await refreshToken();
    return newToken;
  },
);

On a 401, the interceptor calls tokenRefresher, updates the stored token, and retries the original request once. Infinite loops are prevented via a per-request flag.

Configurable Pagination #

// Offset-based with custom field keys:
final result = await api.getPaginated<User>(
  '/users',
  parser: User.fromJson,
  paginationConfig: const PaginationConfig(
    itemsKey: 'data',
    currentPageKey: 'page',
    totalPagesKey: 'pages',
    totalItemsKey: 'count',
  ),
);

// Cursor-based:
final result = await api.getPaginated<User>(
  '/users',
  parser: User.fromJson,
  paginationStrategy: const CursorPaginationStrategy(),
);
print(result.nextCursor); // cursor for the next page

Caching with ETag & Deduplication #

final api = ApiKit(
  baseUrl: 'https://api.example.com',
  useCache: true,
  cacheMaxAge: 300, // 5 minutes
);
// Concurrent identical GETs share a single in-flight request automatically.

Web/WASM-Ready Connectivity #

// Pure-Dart / Web: no-op checker is the default — no native plugin required.
final api = ApiKit(baseUrl: 'https://api.example.com');

// Flutter: inject a connectivity_plus-backed checker if desired.
final api = ApiKit(
  baseUrl: 'https://api.example.com',
  connectivityChecker: MyConnectivityChecker(),
);

Injectable Logger #

final silentLogger = ApiLogger(level: LogLevel.none);
final api = ApiKit(
  baseUrl: 'https://api.example.com',
  logger: silentLogger,
);

cURL Request Logging #

When making HTTP requests, the default logger automatically logs the equivalent cURL command to the console (at info level). This allows developers to copy the request and paste it directly into Postman, Insomnia, or a command-line terminal to test and debug endpoints easily.

Example output:

[ℹ️ INFO 15:54:10] --> POST https://api.example.com/login
[ℹ️ INFO 15:54:10] cURL:
curl --location 'https://api.example.com/login' --request POST \
  --header 'Content-Type: application/json' \
  --data-raw '{"username":"admin","password":"password"}'

Cache & Retry Settings #

final api = ApiKit(
  baseUrl: 'https://api.example.com',
  token: 'your-initial-auth-token',
  maxRetries: 3,
  retryDelayBase: 1000, // base delay in ms for exponential backoff
  checkConnectivity: true,
  useCache: true,
  cacheMaxAge: 300, // cache expiration in seconds (5 minutes)
  connectTimeout: 30000,
  receiveTimeout: 30000,
  sendTimeout: 30000,
);

Dynamic Token Updates #

api.updateToken('new-user-token');
api.clearToken();

Interceptors #

api.addInterceptor(
  onRequest: (options) async {
    options.headers['X-Custom-Header'] = 'custom-value';
    return options;
  },
  onResponse: (response) async {
    print('Response status: ${response.statusCode}');
    return response;
  },
  onError: (error) async {
    print('Request failed: ${error.message}');
    return error;
  },
);

Platform Support #

api_network_kit is verified compatible with all six Flutter-supported targets. The library contains no platform-specific imports (dart:io, dart:html, Platform.*, kIsWeb) and is not a federated plugin — it is pure Dart built on Dio, which supports all platforms natively.

Platform Compilation Core methods File methods Status
Android Fully supported
iOS Fully supported
Web ⚠️ Throws Supported with caveat
WASM ⚠️ Throws Supported with caveat
Linux Fully supported
macOS Fully supported
Windows Fully supported

How Web/WASM compatibility was achieved #

In v1.0.x, the package depended on connectivity_plus — a native plugin that blocked Web and WASM compilation. In v1.1.0, connectivity checking was decoupled behind the ConnectivityChecker interface with a NoOpConnectivityChecker default that always reports a connection. connectivity_plus was moved to dev_dependencies, so pure-Dart, Web, and WASM consumers no longer pull a native plugin. Flutter consumers who want real connectivity checks can inject a connectivity_plus-backed ConnectivityChecker implementation.

Runtime limitation: uploadFile() and downloadFile() on Web/WASM #

The uploadFile() and downloadFile() methods rely on Dio's MultipartFile.fromFile() and Dio.download() respectively, which access the filesystem via dart:io under the hood. These two methods will throw at runtime on Flutter Web and WASM when called. They do not block compilation and do not affect any other method (get, post, put, delete, getPaginated, getMap, getList, getRaw, etc. are fully platform- agnostic).

On Web, use MultipartFile.fromBytes() with post() for uploads instead of uploadFile().


API Reference #

Requests #

  • get<T>() / getPaginated<T>()
  • getMap() / getList() / getRaw()
  • post<T>() / postMap() / postList()
  • put<T>() / patch<T>() / delete<T>()
  • uploadFile<T>() / uploadFiles<T>() / downloadFile()

Exceptions #

All exceptions extend ApiBaseException and carry statusCode, data, and errors from the server response body.

  • NetworkException, ServerException, NoInternetException, TimeoutException, ApiException
  • BadRequestException (400), UnauthorizedException (401), ForbiddenException (403), NotFoundException (404), ConflictException (409), UnprocessableEntityException (422), TooManyRequestsException (429)

Pagination #

  • PaginationStrategy (interface)
  • OffsetPaginationStrategy, CursorPaginationStrategy
  • PaginationConfig (configurable field keys)

Caching #

  • CacheStore (interface)
  • ApiCache (in-memory, TTL + ETag)
  • RequestDeduplicator

Connectivity #

  • ConnectivityChecker (interface)
  • NoOpConnectivityChecker (default)

For a complete set of features, check the example directory for detailed implementations.


Additional Documentation #

7
likes
160
points
584
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A batteries-included, no-codegen Dio wrapper for Flutter/Dart featuring typed parsing, resilient retry, automatic token refresh, caching, pagination, and WASM-ready checks.

Repository (GitHub)
View/report issues

Topics

#http #network #api-client #dio #rest

License

MIT (license)

Dependencies

dio

More

Packages that depend on api_network_kit