ispectify_dio 4.3.3
ispectify_dio: ^4.3.3 copied to clipboard
An additional package for Dio (logging and handling).
π Overview #
ISpectify Dio provides seamless integration between Dio HTTP client and the ISpectify logging system.
π HTTP Logging β’ π Response Tracking β’ β Error Handling β’ β‘ Performance
Streamline your HTTP debugging workflow by automatically capturing and logging all Dio HTTP client interactions. Perfect for monitoring API calls, debugging network issues, and tracking performance metrics.
π― Key Features #
- π HTTP Request Logging: Automatic logging of all Dio requests
- π Response Tracking: Detailed response logging with timing information
- β Error Handling: Comprehensive error logging with stack traces
- π Request Inspection: Headers, body, and parameter logging
- π Sensitive Data Redaction: Centralized redaction for headers and bodies (enabled by default, configurable)
- β‘ Performance Metrics: Request/response timing and size tracking
- ποΈ Configurable: Flexible configuration options for different environments
π§ Configuration Options #
Basic Setup #
final Dio dio = Dio(
BaseOptions(
baseUrl: 'https://api.example.com',
),
);
// Initialize in ISpect.run onInit callback
ISpect.run(
() => runApp(MyApp()),
logger: iSpectify,
onInit: () {
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
settings: const ISpectDioInterceptorSettings(
printRequestHeaders: true,
),
),
);
},
);
Sensitive Data Redaction #
Redaction is enabled by default. Disable globally via settings or provide a custom redactor.
// Disable redaction
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
settings: const ISpectDioInterceptorSettings(enableRedaction: false),
),
);
// Provide a custom redactor
final redactor = RedactionService();
redactor.ignoreKeys(['x-debug']);
redactor.ignoreValues(['sample-token']);
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
redactor: redactor,
),
);
Advanced Configuration with Filters #
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
settings: const ISpectDioInterceptorSettings(
printRequestHeaders: true,
// requestFilter: (requestOptions) =>
// requestOptions.path != '/sensitive-endpoint',
// responseFilter: (response) => response.statusCode != 404,
// errorFilter: (error) => error.response?.statusCode != 404,
),
),
);
Multiple Dio Instances #
final Dio mainDio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
final Dio uploadDio = Dio(BaseOptions(baseUrl: 'https://upload.example.com'));
mainDio.interceptors.add(ISpectDioInterceptor(iSpectify: iSpectify));
uploadDio.interceptors.add(ISpectDioInterceptor(iSpectify: iSpectify));
π¦ Installation #
Add ispectify_dio to your pubspec.yaml:
dependencies:
ispectify_dio: ^4.3.3
β οΈ Security & Production Guidelines #
π¨ IMPORTANT: ISpect is a debugging tool and should NEVER be included in production builds
π Production Safety #
ISpect contains sensitive debugging information and should only be used in development and staging environments. To ensure ISpect is completely removed from production builds, use the following approach:
β Recommended Setup with Dart Define Constants #
1. Create environment-aware initialization:
// main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// Use dart define to control ISpect inclusion
const bool kEnableISpect = bool.fromEnvironment('ENABLE_ISPECT', defaultValue: false);
void main() {
if (kEnableISpect) {
// Initialize ISpect only in development/staging
_initializeISpect();
} else {
// Production initialization without ISpect
runApp(MyApp());
}
}
void _initializeISpect() {
// ISpect initialization code here
// This entire function will be tree-shaken in production
}
2. Build Commands:
# Development build (includes ISpect)
flutter run --dart-define=ENABLE_ISPECT=true
# Staging build (includes ISpect)
flutter build appbundle --dart-define=ENABLE_ISPECT=true
# Production build (ISpect completely removed via tree-shaking)
flutter build appbundle --dart-define=ENABLE_ISPECT=false
# or simply:
flutter build appbundle # defaults to false
3. Conditional Widget Wrapping:
Widget build(BuildContext context) {
return MaterialApp(
// Conditionally add ISpectBuilder in MaterialApp builder
builder: (context, child) {
if (kEnableISpect) {
return ISpectBuilder(child: child ?? const SizedBox.shrink());
}
return child ?? const SizedBox.shrink();
},
home: Scaffold(/* your app content */),
);
}
π‘οΈ Security Benefits #
- β Zero Production Footprint: Tree-shaking removes all ISpect code from release builds
- β No Sensitive Data Exposure: Debug information never reaches production users
- β Performance Optimized: No debugging overhead in production
- β Compliance Ready: Meets security requirements for app store releases
π Verification #
To verify ISpect is not included in your production build:
# Build release APK and check size difference
flutter build apk --dart-define=ENABLE_ISPECT=false --release
flutter build apk --dart-define=ENABLE_ISPECT=true --release
# Use flutter tools to analyze bundle
flutter analyze --dart-define=ENABLE_ISPECT=false
π Quick Start #
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:ispect/ispect.dart';
import 'package:ispectify_dio/ispectify_dio.dart';
// Use dart define to control ISpectify Dio integration
const bool kEnableISpectDio = bool.fromEnvironment('ENABLE_ISPECT', defaultValue: false);
final Dio dio = Dio(
BaseOptions(
baseUrl: 'https://jsonplaceholder.typicode.com',
),
);
void main() {
if (kEnableISpectDio) {
_initializeWithISpect();
} else {
// Production initialization without ISpect
runApp(MyApp());
}
}
void _initializeWithISpect() {
final ISpectify iSpectify = ISpectifyFlutter.init();
ISpect.run(
() => runApp(MyApp()),
logger: iSpectify,
onInit: () {
// Add ISpectify Dio interceptor only in development/staging
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
settings: const ISpectDioInterceptorSettings(
printRequestHeaders: true,
),
),
);
},
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ISpectify Dio Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// HTTP requests will be logged only when ISpect is enabled
dio.get<dynamic>('/posts/1');
},
child: const Text('Send GET Request'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// Error requests are also logged (when enabled)
dio.get<dynamic>('/invalid-endpoint');
},
child: const Text('Send Error Request'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// Upload file with FormData
final FormData formData = FormData();
formData.files.add(MapEntry(
'file',
MultipartFile.fromBytes(
[1, 2, 3],
filename: 'file.txt',
),
));
dio.post<dynamic>('/upload', data: formData);
},
child: const Text('Upload File'),
),
],
),
),
),
);
}
}
βοΈ Advanced Configuration #
π‘οΈ Production-Safe HTTP Logging #
// Create a factory for conditional Dio setup
class DioFactory {
static const bool _isEnabled = bool.fromEnvironment('ENABLE_ISPECT', defaultValue: false);
static Dio createDio({
String baseUrl = '',
ISpectify? iSpectify,
}) {
final dio = Dio(BaseOptions(baseUrl: baseUrl));
// Only add interceptor when ISpect is enabled
if (_isEnabled && iSpectify != null) {
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
settings: ISpectDioInterceptorSettings(
printRequestHeaders: kDebugMode,
enableRedaction: true, // Always enable redaction for security
),
),
);
}
return dio;
}
}
// Usage
final dio = DioFactory.createDio(
baseUrl: 'https://api.example.com',
iSpectify: ISpect.logger,
);
π Environment-Specific Configuration #
class DioConfig {
static ISpectDioInterceptorSettings getSettings() {
const environment = String.fromEnvironment('ENVIRONMENT', defaultValue: 'development');
switch (environment) {
case 'development':
return const ISpectDioInterceptorSettings(
printRequestHeaders: true,
printResponseHeaders: true,
enableRedaction: false, // Allow full debugging in dev
);
case 'staging':
return const ISpectDioInterceptorSettings(
printRequestHeaders: true,
printResponseHeaders: false,
enableRedaction: true, // Enable redaction in staging
);
default: // production
return const ISpectDioInterceptorSettings(
printRequestHeaders: false,
printResponseHeaders: false,
enableRedaction: true,
);
}
}
}
ποΈ Conditional Interceptor Setup #
void setupDioInterceptors(Dio dio, ISpectify? iSpectify) {
const isISpectEnabled = bool.fromEnvironment('ENABLE_ISPECT', defaultValue: false);
if (isISpectEnabled && iSpectify != null) {
// Custom redactor for sensitive data
final redactor = RedactionService();
redactor.ignoreKeys(['authorization', 'x-api-key']);
redactor.ignoreValues(['password', 'token']);
dio.interceptors.add(
ISpectDioInterceptor(
iSpectify: iSpectify,
redactor: redactor,
settings: DioConfig.getSettings(),
),
);
}
// Add other production interceptors here
dio.interceptors.add(LogInterceptor(requestBody: false, responseBody: false));
}
π Examples #
See the example/ directory for complete integration examples with different Dio configurations.
ποΈ Architecture #
ISpectifyDio integrates with the Dio HTTP client through interceptors:
| Component | Description |
|---|---|
| Dio Interceptor | Captures HTTP requests and responses |
| Request Logger | Logs request details (headers, body, params) |
| Response Logger | Logs response data and timing |
| Error Handler | Captures and logs HTTP errors |
| Performance Tracker | Measures request/response times |
π€ Contributing #
Contributions are welcome! Please read our contributing guidelines and submit pull requests to the main branch.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Related Packages #
- ispectify - Foundation logging system
- ispectify_http - Standard HTTP client integration
- ispect - Main debugging interface
- dio - HTTP client for Dart