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