Skip to content

Instantly share code, notes, and snippets.

@arafaysaleem
Created July 4, 2022 08:01
Show Gist options
  • Save arafaysaleem/da0d28ebedf54621c56c2edee83c73cc to your computer and use it in GitHub Desktop.
Save arafaysaleem/da0d28ebedf54621c56c2edee83c73cc to your computer and use it in GitHub Desktop.
Logging Interceptor For Network Layer
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:dio/dio.dart';
//helpers
import '../../../helpers/typedefs.dart';
/// A class that intercepts network requests for logging purposes only. This is
/// the second interceptor in case of both request and response.
///
/// ** This interceptor doesn't modify the request or response in any way. And
/// only works in `debug` mode **
class LoggingInterceptor extends Interceptor {
/// This method intercepts an out-going request before it reaches the
/// destination.
///
/// [options] contains http request information and configuration.
/// [handler] is used to forward, resolve, or reject requests.
///
/// This method is used to log details of all out going requests, then pass
/// it on after that. It may again be intercepted if there are any
/// after it. If none, it is passed to [Dio].
///
/// The [RequestInterceptorHandler] in each method controls the what will
/// happen to the intercepted request. It has 3 possible options:
///
/// - [handler.next]/[super.onRequest], if you want to forward the request.
/// - [handler.resolve]/[super.onResponse], if you want to resolve the
/// request with your custom [Response]. All ** request ** interceptors are ignored.
/// - [handler.reject]/[super.onError], if you want to fail the request
/// with your custom [DioError].
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
final httpMethod = options.method.toUpperCase();
final url = options.baseUrl + options.path;
debugPrint('--> $httpMethod $url'); //GET www.example.com/mock_path/all
debugPrint('\tHeaders:');
options.headers.forEach((k, Object? v) => debugPrint('\t\t$k: $v'));
if (options.queryParameters.isNotEmpty) {
debugPrint('\tqueryParams:');
options.queryParameters
.forEach((k, Object? v) => debugPrint('\t\t$k: $v'));
}
if (options.data != null) {
debugPrint('\tBody: ${options.data}');
}
debugPrint('--> END $httpMethod');
return super.onRequest(options, handler);
}
/// This method intercepts an incoming response before it reaches Dio.
///
/// [response] contains http [Response] info.
/// [handler] is used to forward, resolve, or reject responses.
///
/// This method is used to log all details of incoming responses, then pass
/// it on after that. It may again be intercepted if there are any
/// after it. If none, it is passed to [Dio].
///
/// The [RequestInterceptorHandler] in each method controls the what will
/// happen to the intercepted response. It has 3 possible options:
///
/// - [handler.next]/[super.onRequest], if you want to forward the [Response].
/// - [handler.resolve]/[super.onResponse], if you want to resolve the
/// [Response] with your custom data. All ** response ** interceptors are ignored.
/// - [handler.reject]/[super.onError], if you want to fail the response
/// with your custom [DioError].
@override
void onResponse(
Response response,
ResponseInterceptorHandler handler,
) {
debugPrint('<-- RESPONSE');
debugPrint('\tStatus code: ${response.statusCode}');
if (response.statusCode == 304) {
debugPrint('\tSource: Cache');
} else {
debugPrint('\tSource: Network');
}
debugPrint('\tResponse: ${response.data}');
debugPrint('<-- END HTTP');
return super.onResponse(response, handler);
}
/// This method intercepts any exceptions thrown by Dio, or passed from a
/// previous interceptor.
///
/// [dioError] contains error info when the request failed.
/// [handler] is used to forward, resolve, or reject errors.
///
/// This method is used to log all details of the error arising due to the
/// failed request, then pass it on after that. It may again be intercepted
/// if there are any after it. If none, it is passed to [Dio].
///
/// ** The structure of response in case of errors is dependant on the API and
/// may not always be the same. It might need changing according to your
/// own API. **
///
/// The [RequestInterceptorHandler] in each method controls the what will
/// happen to the intercepted error. It has 3 possible options:
///
/// - [handler.next]/[super.onRequest], if you want to forward the [Response].
/// - [handler.resolve]/[super.onResponse], if you want to resolve the
/// [Response] with your custom data. All ** error ** interceptors are ignored.
/// - [handler.reject]/[super.onError], if you want to fail the response
/// with your custom [DioError].
@override
void onError(
DioError dioError,
ErrorInterceptorHandler handler,
) {
debugPrint('--> ERROR');
final httpMethod = dioError.requestOptions.method.toUpperCase();
final url = dioError.requestOptions.baseUrl + dioError.requestOptions.path;
debugPrint('\tMETHOD: $httpMethod'); // GET
debugPrint('\tURL: $url'); // URL
if (dioError.response != null) {
debugPrint('\tStatus code: ${dioError.response!.statusCode}');
if (dioError.response!.data != null) {
final headers =
dioError.response!.data['headers'] as JSON; //API Dependant
final message = headers['message'] as String; //API Dependant
final code = headers['code'] as String; //API Dependant
debugPrint('\tException: $code');
debugPrint('\tMessage: $message');
if (headers.containsKey('data')) {
//API Dependant
final data = headers['data'] as List<Object?>;
if (data.isNotEmpty) {
debugPrint('\tData: $data');
}
}
} else {
debugPrint('${dioError.response!.data}');
}
} else if (dioError.error is SocketException) {
const message = 'No internet connectivity';
debugPrint('\tException: FetchDataException');
debugPrint('\tMessage: $message');
} else {
debugPrint('\tUnknown Error');
}
debugPrint('<-- END ERROR');
return super.onError(dioError, handler);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment