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

A Flutter wrapper around Dio HTTP client providing unified API service interface with secure token management, functional error handling, and cross-platform support.

dio_bridge #

pub package License: MIT

A Flutter wrapper around Dio HTTP client providing unified API service interface with secure token management, functional error handling, and cross-platform support.


Table of Contents #


Features #

  • HTTP Methods: Full support for GET, POST, PUT, DELETE, PATCH with type-safe responses
  • Token Management: Secure encrypted storage on native platforms, localStorage on web, automatic Bearer header injection, and token refresh
  • Error Handling: Functional error handling using Either monad from fpdart
  • Progress Tracking: Built-in upload/download progress callbacks
  • Flexible Configuration: Custom headers, query parameters, response types, and interceptors
  • Automatic Token Refresh: Seamless 401 handling with retry logic
  • Cross-Platform: Works on iOS, Android, macOS, Windows, Linux, and Web

Installation #

dependencies:
  dio_bridge: ^1.0.0
flutter pub get

Quick Start #

import 'package:dio_bridge/dio_bridge.dart';

void main() async {
  final dio = Dio(BaseOptions(
    baseUrl: 'https://api.example.com',
  ));

  final apiService = DioBridgeService(dio: dio);
  await apiService.initialize();

  // Make a simple GET request
  final result = await apiService.getMethod<String>('/users');
  result.fold(
    (error) => print('Error: ${error.message}'),
    (response) => print('Success: ${response.data}'),
  );
}

Usage #

HTTP Methods #

All HTTP methods return Either<DioException, Response<T>> for functional error handling:

// GET request
final result = await apiService.getMethod<String>('/users');

// POST with body
final createResult = await apiService.postMethod<Map<String, dynamic>>(
  '/users',
  body: {'name': 'John', 'email': 'john@example.com'},
);

// PUT request
await apiService.putMethod('/users/1', body: {'name': 'Jane'});

// DELETE request
await apiService.deleteMethod('/users/1');

// PATCH request
await apiService.patchMethod('/users/1', body: {'active': false});

Request Configuration #

Use DioBridgeOption for custom headers, query parameters, and progress tracking:

final result = await apiService.getMethod<String>(
  '/search',
  option: DioBridgeOption(
    header: DioBridgeHeader.basic(headers: {'Custom-Header': 'value'}),
    query: {'q': 'flutter', 'limit': '10'},
    onReceiveProgress: (current, total) => print('Progress: ${(current/total*100).round()}%'),
    responseType: DioBridgeResponseType.json(),
  ),
);

Token Management #

// Set tokens (securely stored on native platforms, localStorage on web)
await apiService.setTokens(DioBridgeTokenPair(
  accessToken: 'your-access-token',
  refreshToken: 'your-refresh-token',
  expiresAt: DateTime.now().add(Duration(hours: 1)),
));

// Check authentication status
final isAuth = await apiService.isAuthenticated;
final isExpired = await apiService.isTokenExpired;

// Get current tokens
final tokens = await apiService.currentTokens;

// Clear tokens
await apiService.clearTokens();

Note: On web platforms, tokens are stored using localStorage and are not cryptographically secure. On native platforms (iOS, Android, desktop), tokens are stored securely using encrypted storage.

Automatic Token Refresh #

Configure automatic token refresh for 401 responses:

final apiService = DioBridgeService(
  dio: dio,
  tokenRefreshCallback: (refreshToken) async {
    final response = await dio.post('/auth/refresh',
      data: {'refreshToken': refreshToken});

    return right(DioBridgeTokenPair(
      accessToken: response.data['accessToken'],
      refreshToken: response.data['refreshToken'],
    ));
  },
  onTokenExpired: () {
    // Navigate to login screen
    print('Token expired - redirecting to login');
  },
);

Error Handling #

All methods return Either<DioException, Response<T>>. Handle errors functionally:

final result = await apiService.postMethod('/api/data', body: data);

result.fold(
  (error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
        showError('Connection timeout');
        break;
      case DioExceptionType.badResponse:
        showError('Server error: ${error.response?.statusCode}');
        break;
      default:
        showError('Network error: ${error.message}');
    }
  },
  (response) {
    // Handle success
    final responseData = response.data;
  },
);

Request Cancellation #

Cancel requests using CancelToken:

final cancelToken = CancelToken();
final result = await apiService.getMethod('/slow-endpoint', cancelToken: cancelToken);

// Cancel the request
cancelToken.cancel('Request cancelled by user');

API Reference #

Classes #

DioBridgeService

Abstract factory class providing the main API service interface with HTTP methods and token management.

Constructors

DioBridgeService({
  required Dio dio,
  List<Interceptor>? interceptors,
  Future<Either<String, DioBridgeTokenPair>> Function(String refreshToken)?
    tokenRefreshCallback,
  VoidCallback? onTokenExpired,
})

Methods

Method Returns Description
initialize() Future<void> Initializes the service and token manager
getMethod<T>(String endpoint, {DioBridgeOption? option, CancelToken? cancelToken}) Future<Either<DioException, Response<T>>> Performs GET request
postMethod<T>(String endpoint, {DioBridgeOption? option, dynamic body, CancelToken? cancelToken}) Future<Either<DioException, Response<T>>> Performs POST request
putMethod<T>(String endpoint, {DioBridgeOption? option, dynamic body, CancelToken? cancelToken}) Future<Either<DioException, Response<T>>> Performs PUT request
deleteMethod<T>(String endpoint, {DioBridgeOption? option, dynamic body, CancelToken? cancelToken}) Future<Either<DioException, Response<T>>> Performs DELETE request
patchMethod<T>(String endpoint, {DioBridgeOption? option, dynamic body, CancelToken? cancelToken}) Future<Either<DioException, Response<T>>> Performs PATCH request
setTokens(DioBridgeTokenPair tokenPair) Future<void> Stores authentication tokens securely
clearTokens() Future<void> Removes stored authentication tokens
currentTokens Future<DioBridgeTokenPair?> Returns currently stored tokens
isAuthenticated Future<bool> Checks if user is authenticated
isTokenExpired Future<bool> Checks if current token is expired

DioBridgeOption

Configuration class for customizing HTTP requests with headers, query parameters, and progress callbacks.

Constructors

const DioBridgeOption({
  this.query,
  this.onReceiveProgress,
  this.onSendProgress,
  this.header = const DioBridgeHeader.basic(),
  this.responseType = const DioBridgeResponseType.json(),
})

Properties

Property Type Description
header DioBridgeHeader Request headers configuration
query Map<String, dynamic>? Query parameters
onReceiveProgress OnPercentage? Download progress callback
onSendProgress OnPercentage? Upload progress callback
responseType DioBridgeResponseType Response type configuration

DioBridgeHeader

Sealed class providing predefined header configurations for different content types.

Constructors

const DioBridgeHeader.basic({Map<String, String>? headers})
const DioBridgeHeader.formData({Map<String, String>? headers})
const DioBridgeHeader.data({Map<String, String>? headers})

DioBridgeResponseType

Sealed class defining available response types for HTTP requests.

Constructors

const DioBridgeResponseType.json()
const DioBridgeResponseType.stream()
const DioBridgeResponseType.plain()
const DioBridgeResponseType.bytes()

DioBridgeTokenPair

Immutable class representing authentication token pair with optional expiration.

Constructors

const DioBridgeTokenPair({
  required String accessToken,
  String? refreshToken,
  DateTime? expiresAt,
})

Properties

Property Type Description
accessToken String Access token for authentication
refreshToken String? Refresh token for token renewal
expiresAt DateTime? Token expiration timestamp
isExpired bool Whether the token is expired

Extensions #

DioBridgeOptionEx on DioBridgeOption

Extension providing conversion to Dio Options.

Method/Getter Returns Description
requestOptions Options Converts to Dio Options object

Example:

final option = DioBridgeOption(
  header: DioBridgeHeader.basic(),
  responseType: DioBridgeResponseType.json(),
);

final dioOptions = option.requestOptions; // Options object

DioBridgeHeaderEx on DioBridgeHeader

Extension providing header map conversion.

Method/Getter Returns Description
toMap Map<String, String> Converts to header map with appropriate content-type

Example:

final header = DioBridgeHeader.basic(headers: {'Custom': 'value'});
final headerMap = header.toMap;
// {'accept': 'application/json', 'content-type': 'application/json; charset=utf-8', 'Custom': 'value'}

DioBridgeResponseTypeEx on DioBridgeResponseType

Extension providing conversion to Dio ResponseType.

Method/Getter Returns Description
toDio ResponseType Converts to Dio ResponseType enum

Example:

final responseType = DioBridgeResponseType.json();
final dioResponseType = responseType.toDio; // ResponseType.json

Typedefs #

OnPercentage

typedef OnPercentage = void Function(int currentBytes, int totalBytes);

Callback function for tracking upload/download progress with current and total bytes.


Complete Examples #

Complete API Service Setup #

Complete example showing full service setup with token management, custom interceptors, and error handling:

import 'package:dio_bridge/dio_bridge.dart';
import 'package:dio/dio.dart';

class ApiService {
  late final DioBridgeService _service;

  Future<void> initialize() async {
    final dio = Dio(BaseOptions(
      baseUrl: 'https://api.example.com',
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
    ));

    _service = DioBridgeService(
      dio: dio,
      interceptors: [
        LogInterceptor(requestBody: true, responseBody: true),
      ],
      tokenRefreshCallback: _refreshToken,
      onTokenExpired: _handleTokenExpired,
    );

    await _service.initialize();
  }

  Future<Either<String, DioBridgeTokenPair>> _refreshToken(String refreshToken) async {
    try {
      final response = await Dio().post(
        'https://api.example.com/auth/refresh',
        data: {'refreshToken': refreshToken},
      );

      return right(DioBridgeTokenPair(
        accessToken: response.data['accessToken'],
        refreshToken: response.data['refreshToken'],
        expiresAt: DateTime.now().add(Duration(hours: 1)),
      ));
    } catch (e) {
      return left('Token refresh failed');
    }
  }

  void _handleTokenExpired() {
    // Navigate to login screen
    print('Token expired - redirecting to login');
  }

  // Authentication methods
  Future<Either<DioException, Response<Map<String, dynamic>>>> login(
    String email,
    String password,
  ) async {
    final result = await _service.postMethod<Map<String, dynamic>>(
      '/auth/login',
      body: {'email': email, 'password': password},
    );

    // Store tokens on successful login
    result.fold(
      (error) => null,
      (response) async {
        final tokenData = response.data;
        if (tokenData != null) {
          await _service.setTokens(DioBridgeTokenPair(
            accessToken: tokenData['accessToken'],
            refreshToken: tokenData['refreshToken'],
            expiresAt: DateTime.now().add(Duration(hours: 1)),
          ));
        }
      },
    );

    return result;
  }

  // Data methods with automatic token handling
  Future<Either<DioException, Response<List<dynamic>>>> getUsers() {
    return _service.getMethod<List<dynamic>>('/users');
  }

  Future<Either<DioException, Response<Map<String, dynamic>>>> createUser(
    Map<String, dynamic> userData,
  ) {
    return _service.postMethod<Map<String, dynamic>>(
      '/users',
      body: userData,
    );
  }

  Future<Either<DioException, Response<Map<String, dynamic>>>> uploadFile(
    String filePath,
    void Function(int current, int total) onProgress,
  ) {
    return _service.postMethod<Map<String, dynamic>>(
      '/upload',
      option: DioBridgeOption(
        header: DioBridgeHeader.formData(),
        onSendProgress: onProgress,
      ),
      body: FormData.fromMap({
        'file': MultipartFile.fromFileSync(filePath),
      }),
    );
  }

  Future<void> logout() async {
    await _service.clearTokens();
  }
}

License #

MIT License

Copyright (c) 2026 Mustafa Fahimi

Made with ❤️ by Mustafa Fahimi

0
likes
150
points
0
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter wrapper around Dio HTTP client providing unified API service interface with secure token management, functional error handling, and cross-platform support.

Repository (GitHub)
View/report issues

Topics

#http #api #dio #networking #flutter

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

database_bridge, dio, flutter, fpdart, freezed_annotation, web

More

Packages that depend on dio_bridge