network_caller_http 1.0.1 copy "network_caller_http: ^1.0.1" to clipboard
network_caller_http: ^1.0.1 copied to clipboard

Production-ready HTTP networking for Flutter. Auto-handles tokens, refresh, retry, logging, and typed errors.

network_caller_http

Production-ready HTTP networking for Flutter. Zero boilerplate.
Built on package:http — just configure once and call.

pub package License Platform


Features #

Feature Description
Generic Responses NetworkResponse<T> — parse to any model with a one-line parser
Token Management Auto-refresh on 401, concurrent-safe Completer lock, secure storage
4 Auth Strategies Bearer, API Key, Basic Auth, Custom — swap with one line
Typed Exceptions 10 exception types — pattern-match instead of string checking
Retry with Backoff Configurable retry policy, exponential backoff, Retry-After support
Request Cancellation HttpCancelToken — cancel any in-flight request
Per-Request Timeout Override global timeout on any individual call
Query Parameters First-class queryParameters map on GET (and all methods)
Response Headers Access pagination cursors, ETag, rate-limit info on every response
ResponseType JSON (default), plain text, or raw bytes
Multipart Upload File upload with progress callback
Middleware NetworkMiddleware — hook into request/response/error pipeline
Logging ConsoleNetworkLogger or implement your own
Form-Encoded Auto-detected by Content-Type header
Resource Cleanup dispose() to close the HTTP client

Installation #

dependencies:
  network_caller_http: ^1.0.0

This automatically pulls in network_caller_core. You only need one import.

Quick Start #

import 'package:network_caller_http/network_caller_http.dart';

// 1. Create caller (once, at app startup)
final caller = HttpNetworkCaller(
  config: const NetworkConfig(baseUrl: 'https://api.example.com'),
  tokenStorage: SecureTokenStorage(),
);

// 2. Make requests
final res = await caller.get<User>(
  url: '/profile',
  withToken: true,
  parser: (json) => User.fromJson(json),
);

if (res.isSuccess) {
  print(res.data!.name);
} else {
  print(res.exception); // typed NetworkException
}

Usage Examples #

GET with Query Parameters #

final res = await caller.get<List<Post>>(
  url: '/posts',
  queryParameters: {'userId': '1', 'page': '2'},
  parser: (json) => (json as List).map((e) => Post.fromJson(e)).toList(),
);

POST with Body #

final res = await caller.post<Post>(
  url: '/posts',
  body: {'title': 'New Post', 'body': 'Content here', 'userId': 1},
  withToken: true,
  parser: (json) => Post.fromJson(json),
);

Token Management #

// After login — save tokens
await caller.tokenManager.saveTokens(
  accessToken: loginResponse.accessToken,
  refreshToken: loginResponse.refreshToken,
);

// On logout — clear tokens
await caller.tokenManager.clearTokens();

// 401 auto-refresh happens automatically when withToken: true

Error Handling #

final res = await caller.get(url: '/data');

if (!res.isSuccess) {
  switch (res.exception) {
    case NoConnectionException():
      showSnackbar('No internet connection');
    case NetworkTimeoutException():
      showSnackbar('Request timed out');
    case UnauthorizedException():
      navigateToLogin();
    case RateLimitException(:final retryAfter):
      showSnackbar('Too many requests. Retry in $retryAfter');
    case ServerException(:final statusCode):
      showSnackbar('Server error ($statusCode)');
    case ClientException(:final statusCode):
      showSnackbar('Error ($statusCode): ${res.message}');
    default:
      showSnackbar(res.message ?? 'Something went wrong');
  }
}

Cancel a Request #

final cancelToken = HttpCancelToken();

// Start request
final future = caller.get(url: '/search?q=flutter', cancelToken: cancelToken);

// Cancel it (e.g., user navigated away)
cancelToken.cancel('User left the page');

final res = await future;
// res.exception is RequestCancelledException

Per-Request Timeout #

final res = await caller.get(
  url: '/slow-endpoint',
  timeout: const Duration(seconds: 60), // override global 15s
);

Retry Policy #

final caller = HttpNetworkCaller(
  config: const NetworkConfig(
    baseUrl: 'https://api.example.com',
    retryPolicy: RetryPolicy.standard(), // 3 retries, exponential backoff
  ),
  tokenStorage: SecureTokenStorage(),
);

// Custom retry
final caller2 = HttpNetworkCaller(
  config: NetworkConfig(
    baseUrl: 'https://api.example.com',
    retryPolicy: RetryPolicy(
      maxRetries: 5,
      initialDelay: Duration(seconds: 1),
      backoffMultiplier: 2.0,
      retryWhen: (code) => code >= 500, // only server errors
    ),
  ),
  tokenStorage: SecureTokenStorage(),
);

Auth Strategies #

// API Key in header
final caller = HttpNetworkCaller(
  config: const NetworkConfig(
    baseUrl: 'https://api.example.com',
    authStrategy: ApiKeyAuthStrategy(
      key: 'your-api-key',
      paramName: 'x-api-key',
      location: ApiKeyLocation.header,
    ),
  ),
  tokenStorage: SecureTokenStorage(),
);

// Basic Auth
final caller2 = HttpNetworkCaller(
  config: const NetworkConfig(
    baseUrl: 'https://api.example.com',
    authStrategy: BasicAuthStrategy(username: 'admin', password: 'secret'),
  ),
  tokenStorage: SecureTokenStorage(),
);

Middleware #

final caller = HttpNetworkCaller(
  config: NetworkConfig(
    baseUrl: 'https://api.example.com',
    middlewares: [
      NetworkMiddleware(
        onRequest: (ctx) async {
          ctx.headers['X-Tenant-Id'] = '12345';
        },
        onResponse: (statusCode, body) async {
          print('Response: $statusCode');
        },
      ),
    ],
  ),
  tokenStorage: SecureTokenStorage(),
);

Wrapped API Responses #

// Your API returns: {"data": {...}, "meta": {"page": 1}}
final caller = HttpNetworkCaller(
  config: NetworkConfig(
    baseUrl: 'https://api.example.com',
    responseUnwrapper: (body) => body['data'], // extracts 'data' before parser
  ),
  tokenStorage: SecureTokenStorage(),
);

File Upload #

final res = await caller.upload<UploadResult>(
  url: '/upload',
  files: [
    NetworkMultipartFile(
      field: 'avatar',
      bytes: imageBytes,
      filename: 'photo.jpg',
      contentType: 'image/jpeg',
    ),
  ],
  fields: {'description': 'Profile photo'},
  withToken: true,
  onProgress: (sent, total) => print('${sent / total * 100}%'),
  parser: (json) => UploadResult.fromJson(json),
);

Choosing HTTP vs Dio #

network_caller_http network_caller_dio
Underlying library package:http package:dio
Package size Lighter Slightly heavier
Interceptors NetworkMiddleware Native Dio Interceptor
Best for Simple apps, minimal deps Advanced apps, complex interceptor chains
API Identical Identical

Both packages implement the same NetworkInterface — switching is a one-line change.

Platform Support #

Android iOS Web macOS Windows Linux

License #

MIT License. See LICENSE for details.

3
likes
160
points
31
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Production-ready HTTP networking for Flutter. Auto-handles tokens, refresh, retry, logging, and typed errors.

Homepage
Repository (GitHub)
View/report issues

Topics

#networking #http #api #rest #http-client

License

MIT (license)

Dependencies

flutter, flutter_secure_storage, http, network_caller_core

More

Packages that depend on network_caller_http