dio_extended 1.0.20 copy "dio_extended: ^1.0.20" to clipboard
dio_extended: ^1.0.20 copied to clipboard

a thin wrapper over the dio HTTP client that simplifies networking in Flutter.

🚀 DioExtended #

A thin, result-based wrapper over dio that makes networking in Flutter clean, safe, and boilerplate-free. #


pub version pub points license platform


DioExtended returns a consistent ApiResult<T> for every request, so error handling and JSON parsing stay simple and predictable. It also ships with ShakeForChucker — shake your device to instantly open the Chucker network inspector.


📑 Table of Contents #

Section Description
✨ Features What you get out of the box
📦 Installation Add the package to your project
⚡ Quick Start Up and running in 30 seconds
🌐 DioExtended The core networking client
🔐 Token Refresh Automatic 401 handling
📳 ShakeForChucker Debug by shaking your phone
❓ FAQ Common questions answered

✨ Features #

Feature Description
🧩 Simplified API Every call returns a clean, typed ApiResult<T> interface.
🔄 Automatic JSON Parsing Decode responses into your models with a simple parseData function.
🔐 Built-in Token Refresh Override one method to auto-handle expired tokens and retry requests.
📳 Shake for Debugging Open the network inspector with a shake gesture — perfect for QA.
🧱 FormData Safe Correctly separates Content-Type handling for FormData vs JSON, even on retry.

📦 Installation #

Add dio_extended to your pubspec.yaml:

dependencies:
  dio_extended: ^1.0.20

Then run:

flutter pub get

Note

chucker_flutter and shake are bundled as dependencies — no need to add them separately.


⚡ Quick Start #

import 'package:dio_extended/diox.dart';

class CrudService extends DioExtended {
  CrudService() : super(baseUrl: 'https://jsonplaceholder.typicode.com');

  Future<ApiResult<List<PostModel>>> getPosts() {
    return callApiRequest<List<PostModel>>(
      request: () => get('/posts'),
      parseData: (data) =>
          (data as List).map((e) => PostModel.fromJson(e)).toList(),
    );
  }
}

// ...

final result = await CrudService().getPosts();
if (result.isSuccess) {
  print(result.data); // 🎉 Typed list of PostModel
} else {
  print(result.message); // ⚠️ Friendly error message
}

🌐 DioExtended: Simplified Networking #

DioExtended is the core of this package. It streamlines HTTP requests and returns a consistent ApiResult<T> object for all calls, making error handling and data parsing straightforward.

🔧 Initialization

Set up your API client with a base URL and default headers. Headers are an async Future, so for static headers simply wrap them in Future.value().

import 'package:dio_extended/diox.dart';

// Static headers
final api = DioExtended(
  baseUrl: 'https://api.example.com',
  headers: Future.value({
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  }),
);

// Async headers (e.g. fetched from secure storage)
final api = DioExtended(
  baseUrl: 'https://api.example.com',
  headers: _buildAuthHeaders(),
);

static Future<Map<String, String>?> _buildAuthHeaders() async {
  await Future.delayed(const Duration(seconds: 3)); // fetch simulation
  return {
    'Authorization': 'Bearer your_token_here',
    'Custom-Header': 'CustomValue',
  };
}

// Access the underlying Dio instance directly when needed
final dioInstance = api.dio;

Prefer a dedicated, independent service? Just extend DioExtended:

class CrudService extends DioExtended {
  CrudService() : super(baseUrl: 'YOUR-BASE-URL');
  // All DioExtended functions are now available here.
}
📥 GET Request Example

Provide a parseData function to map the JSON response into your model.

/// Returns an [ApiResult] with a list of [PostModel] on success.
Future<ApiResult<List<PostModel>>> getPosts() async {
  return await callApiRequest<List<PostModel>>(
    request: () => get('/posts'),
    parseData: (data) => (data as List)
        .map((itemJson) => PostModel.fromJson(itemJson))
        .toList(),
  );
}

/// Single-object variant.
Future<ApiResult<PostModel>> getPost() async {
  return await callApiRequest<PostModel>(
    request: () => get('/posts/1'),
    parseData: (data) => PostModel.fromJson(data),
  );
}

Using callApiRequest handles fetching and parsing. On the business-logic side, just check isSuccess:

final result = await _service.getPosts();
if (result.isSuccess) {
  // ✅ Your logic here — result.data is fully typed
}

🔐 Token Refresh (Optional) #

To handle automatic token refresh, simply override handleTokenExpired. The library calls this callback when a request fails with a 401 status (or a custom code via tokenExpiredCode), then retries the original request.

Tip

  • The interceptor safely separates Content-Type behavior for FormData and non-FormData requests, including on retry.
  • In handleTokenExpired, return auth-related headers only (e.g. Authorization). Avoid setting a global Content-Type from refresh headers.
class CrudService extends DioExtended {
  CrudService()
      : super(
          baseUrl: 'https://jsonplaceholder.typicode.com',
          tokenExpiredCode: 401,
        );

  /// Override to fetch a new auth token when the current one expires.
  @override
  Future<dynamic> handleTokenExpired() async {
    final newHeader = await fetchNewAuth();
    // Return as a Map, e.g. {'Authorization': 'Bearer xxx'}
    return newHeader;
  }
}

📳 ShakeForChucker: Debug with a Shake #

ShakeForChucker integrates with chucker_flutter to open the network inspection UI whenever you shake the device — ideal for developers and QA testers.

⚙️ Setup

Wrap your MaterialApp with ShakeForChucker, and attach ShakeChuckerConfigs.navigatorKey to your app's navigatorKey.

import 'package:flutter/material.dart';
import 'package:dio_extended/diox.dart';

void main() {
  // Initialize Chucker BEFORE runApp().
  ShakeChuckerConfigs.initialize(
    showOnRelease: true,
    showNotification: true,
  );

  runApp(
    ShakeForChucker(
      // Number of shakes needed to trigger Chucker (default: 3)
      shakeCountTriggered: 3,
      child: MaterialApp(
        title: 'DioExtended Demo',
        // Required so Chucker can show its inspector reliably.
        navigatorKey: ShakeChuckerConfigs.navigatorKey,
        home: const MyHomePage(),
      ),
    ),
  );
}

Important

The older navigatorObservers: [ShakeChuckerConfigs.navigatorObserver] approach is now deprecated. Use navigatorKey instead — it works reliably even with nested navigators.


❓ FAQ #

What does callApiRequest return on error?

It returns an ApiResult<T> with isSuccess == false and a human-readable message. No exceptions are thrown for expected network/HTTP failures, so you can branch safely on isSuccess.

Can I still access the raw Dio instance?

Yes. Every DioExtended exposes the underlying client via api.dio, so you can add interceptors, configure timeouts, or call advanced Dio APIs directly.

Does Chucker run in release builds?

Only if you opt in. Set showOnRelease: true in ShakeChuckerConfigs.initialize(...). By default Chucker is intended for debug/QA usage.


Made with ❤️ for the Flutter community.

⭐ If this package helps you, consider starring the repository!

4
likes
130
points
309
downloads

Documentation

API reference

Publisher

verified publisheranonimeact.com

Weekly Downloads

a thin wrapper over the dio HTTP client that simplifies networking in Flutter.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

chucker_flutter, dio, flutter, http_parser, mime, shake

More

Packages that depend on dio_extended