http_client_interceptor 1.0.1
http_client_interceptor: ^1.0.1 copied to clipboard
A Dart package for intercepting and modifying HTTP requests and responses, useful for logging, authentication, and error handling.
http_client_interceptor #
The http_client_interceptor
package provides
a flexible and easy-to-use way to intercept and manipulate HTTP requests and
responses in Dart and Flutter applications. It allows you to add custom behavior
such as logging, authentication, and error handling to your HTTP requests.
Installation #
For Dart #
Run the following command:
dart pub add http_client_interceptor
For Flutter #
Run the following command:
flutter pub add http_client_interceptor
Usage #
To use the http_client_interceptor
package, you need to create an instance
of HttpInterceptorWrapper
and use it with your HTTP client. Here's a basic
example:
For Dart #
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:http_client_interceptor/http_client_interceptor.dart';
void main() {
unawaited(
http.runWithClient(
_myDartApp,
() => HttpClientProxy(
interceptors: [
HttpInterceptorWrapper(
onRequest: (requestOptions) {
// Add custom headers or modify the request
requestOptions.headers['Authorization'] = 'Bearer YOUR_TOKEN';
return OnRequest.next(requestOptions);
},
),
],
),
),
);
}
Future<void> _myDartApp() async {
final client = http.Client();
final response = await client.get(Uri.parse('https://api.example.com/data'));
print(response.body);
}
For Flutter #
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http_client_interceptor/http_client_interceptor.dart';
void main() {
unawaited(
http.runWithClient(
() {
runApp(const MyApp());
},
() => HttpClientProxy(
interceptors: [
HttpInterceptorWrapper(
onRequest: (requestOptions) {
// Add custom headers or modify the request
requestOptions.headers['Authorization'] = 'Bearer YOUR_TOKEN';
return OnRequest.next(requestOptions);
},
),
],
),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// add your code here
}
}
Advanced Usage #
For more advanced usage, you can chain multiple interceptors, handle specific error types, or modify responses before they reach your application. Here's an example:
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:http_client_interceptor/http_client_interceptor.dart';
class LoggingInterceptor extends HttpInterceptor {
@override
FutureOr<OnRequest> onRequest(http.BaseRequest request) {
print('Request: ${request.method} ${request.url}');
return OnRequest.next(request);
}
@override
FutureOr<OnResponse> onResponse(http.StreamedResponse response) {
print('Response: ${response.statusCode}');
return OnResponse.next(response);
}
@override
FutureOr<OnError> onError(
http.BaseRequest request,
Object error,
StackTrace? stackTrace,
) {
print('Error: $error');
return OnError.next(request, error, stackTrace);
}
}
void main() {
unawaited(
http.runWithClient(
_myDartApp,
() => HttpClientProxy(
interceptors: [
LoggingInterceptor(),
// other interceptors
],
),
),
);
}
Future<void> _myDartApp() async {
final client = http.Client();
final response = await client.get(Uri.parse('https://api.example.com/data'));
print(response.body);
}
Compatibility #
http_client_interceptor
works with popular HTTP packages like
Chopper, Retrofit,
and Dio. You can also combine it with other HTTP
clients, like cupertino_http
for iOS and macOS,
cronet_http
for Android, and
RetryClient
,
that are compatible with the http package. This
makes it easy to integrate into various projects and setups.
Note for Flutter's Image Widget #
http_client_interceptor
will not work directly with Flutter's
Image.network
widget
because the NetworkImage
used by the Image.network
widget relies on the
HttpClient
from the
dart:io
package. However, you can achieve this functionality by using the
http_image_provider
package, which
allows you to use the http
package with the Image
widget, enabling the use of http_client_interceptor
.
Using with Chopper #
To use http_client_interceptor
with Chopper, you need to create an instance of
HttpClientProxy
and pass it to the Chopper client. Here's an example:
import 'dart:async';
import 'package:chopper/chopper.dart';
import 'package:http_client_interceptor/http_client_interceptor.dart';
part 'main_chopper.chopper.dart';
Future<void> main() async {
// Create an instance of HttpClientProxy with interceptors.
final httpClient = HttpClientProxy(
interceptors: [
HttpInterceptorWrapper(
onRequest: (request) {
// Add a custom header to the request.
request.headers['customHeader'] = 'customHeaderValue';
return OnRequest.next(request);
},
),
],
);
// Create a ChopperClient using the custom HttpClientProxy.
// This allows Chopper to use the custom HTTP client with interceptors
// instead of the default HTTP client.
final chopper = ChopperClient(
client: httpClient,
services: [PostsService.create()],
);
// Get an instance of the PostsService.
final postsService = chopper.getService<PostsService>();
// Make a GET request to fetch a post by ID.
final response = await postsService.getPost('1');
// Close the ChopperClient's HTTP client.
// Calling close is important to free up resources and avoid potential
// memory leaks.
chopper.httpClient.close();
// Print the response body.
print(response.body);
}
@ChopperApi(baseUrl: 'https://jsonplaceholder.typicode.com/posts')
abstract class PostsService extends ChopperService {
// Factory method to create an instance of PostsService.
static PostsService create([ChopperClient? client]) => _$PostsService(client);
// Define a GET request to fetch a post by ID.
@Get(path: '/{id}')
Future<Response> getPost(@Path() String id);
}
Using with Dio #
To use http_client_interceptor
with Dio, you need to use the
package dio_compatibility_layer
.
This package provides a compatibility layer to make Dio work
with http_client_interceptor
. Here's an example:
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:dio_compatibility_layer/dio_compatibility_layer.dart';
import 'package:http_client_interceptor/http_client_interceptor.dart';
Future<void> main() async {
// Create an instance of HttpClientProxy with interceptors.
final httpClient = HttpClientProxy(
interceptors: [
HttpInterceptorWrapper(
onRequest: (request) {
// Add a custom header to the request.
request.headers['customHeader'] = 'customHeaderValue';
return OnRequest.next(request);
},
),
],
);
// Create a ConversionLayerAdapter using the HttpClientProxy.
// This adapter allows Dio to use the HTTP client from the `http` package
// instead of its default HTTP client.
final dioAdapter = ConversionLayerAdapter(httpClient);
// Instantiate Dio and configure it to use the custom HTTP client adapter.
final dio = Dio()..httpClientAdapter = dioAdapter;
// Make a GET request.
final response = await dio.get(
'https://jsonplaceholder.typicode.com/posts/1',
);
// Close the Dio instance.
// Calling close is important to free up resources and avoid potential
// memory leaks.
dio.close();
// Print the response.
print(response);
}
Using with Retrofit #
Using http_client_interceptor
with Retrofit is very similar to using it with Dio, as both
require the dio_compatibility_layer
package. Here's an example:
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:dio_compatibility_layer/dio_compatibility_layer.dart';
import 'package:http_client_interceptor/http_client_interceptor.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:retrofit/http.dart';
import 'package:retrofit/retrofit.dart';
part 'main_retrofit.g.dart';
Future<void> main() async {
// Create an instance of HttpClientProxy with interceptors.
final httpClient = HttpClientProxy(
interceptors: [
HttpInterceptorWrapper(
onRequest: (request) {
// Add a custom header to the request.
request.headers['customHeader'] = 'customHeaderValue';
return OnRequest.next(request);
},
),
],
);
// Create a ConversionLayerAdapter using the HttpClientProxy.
// This adapter allows Dio to use the HTTP client from the `http` package
// instead of its default HTTP client.
final dioAdapter = ConversionLayerAdapter(httpClient);
// Instantiate Dio and configure it to use the custom HTTP client adapter.
final dio = Dio()..httpClientAdapter = dioAdapter;
// Instantiate a RestClient using the configured Dio instance.
final client = RestClient(dio);
// Make a GET request to fetch a post with ID '1'.
final response = await client.getPost('1');
// Close the Dio instance.
// Calling close is important to free up resources and avoid potential
// memory leaks.
dio.close();
// Print the response.
print(response);
}
@RestApi(baseUrl: 'https://jsonplaceholder.typicode.com/')
abstract class RestClient {
// Factory constructor to create an instance of RestClient using Dio.f
factory RestClient(Dio dio, {String baseUrl}) = _RestClient;
// Define a GET request to fetch a post by its ID.
@GET('/posts/{id}')
Future<Post> getPost(@Path('id') String id);
}
@JsonSerializable()
class Post {
const Post({
required this.userId,
required this.id,
required this.title,
required this.body,
});
factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
final int userId;
final int id;
final String title;
final String body;
@override
String toString() => 'Post id: $id - title: $title';
}
Combined with http compatible clients such as cupertino_http
, cronet_http
and retry
. #
These examples demonstrate how to use http_client_interceptor
with HTTP-compatible clients such as
cupertino_http
, cronet_http
, and retry
. It's important to note that cupertino_http
and cronet_http
are specifically designed for Flutter applications, so they cannot be used
in plain Dart projects. However, the integration principles remain similar across different
client libraries, allowing you to leverage the interceptor functionality alongside the
unique features of each client.
import 'dart:io';
import 'package:cronet_http/cronet_http.dart';
import 'package:cupertino_http/cupertino_http.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/retry.dart';
import 'package:http_client_interceptor/http_client_interceptor.dart';
void main() {
http.runWithClient(
() {
// Ensure that the Flutter framework is properly initialized.
WidgetsFlutterBinding.ensureInitialized();
// Run the Flutter application.
runApp(const MyApp());
},
// Create and configure the HTTP client with interceptors.
_createHttpClient,
);
}
/// The root widget of the application.
///
/// This widget sets up the basic structure of the app, including the home page
/// with an AppBar and a centered image loaded via HTTP.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// Flutter UI code goes here
}
}
/// Creates and configures an HTTP client with interceptors.
///
/// This function sets up a client based on the platform and adds an interceptor.
http.Client _createHttpClient() {
return HttpClientProxy(
// Use RetryClient as the inner client for automatic retries
innerClient: RetryClient(
// Choose the appropriate client based on the platform
switch (Platform.operatingSystem) {
'android' => CronetClient.fromCronetEngine(CronetEngine.build()),
'ios' || 'macos' => CupertinoClient.defaultSessionConfiguration(),
_ => throw UnimplementedError(),
},
),
// Add interceptors to modify requests
interceptors: [
HttpInterceptorWrapper(
onRequest: (requestOptions) {
// Add custom headers or modify the request
requestOptions.headers['Authorization'] = 'Bearer YOUR_TOKEN';
return OnRequest.next(requestOptions);
},
),
],
);
}