Skip to content

Devtools is not showing the HTTP calls on network tab. I use dio package 4.0.6 version for making HTTP calls #9535

@kameshdhana

Description

@kameshdhana

Devtools is not showing the HTTP calls on network tab. I use dio package 4.0.6 version for making HTTP calls


DevTools version: 2.37.3
Connected Device:
CPU / OS: arm64 (64 bit) android
Connected app type: Flutter native (debug build)
Dart Version: 3.5.4
Flutter Version: 3.24.5 / stable
Framework / Engine: dec2ee5c1f / a18df97ca5

This is the api_client.dart I use for endpoint calls
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../../common/utils/flushbar_utils.dart';
import '../api_end_points/uri_constants.dart';
import 'custom_interceptor.dart';
import 'models/request_object.dart';

class APIClient {
late Dio? _dio;
static final _defaultTimeout =
const Duration(minutes: kReleaseMode ? 3 : 6).inMilliseconds;

Map<String, String> get _addAuthHeader => {'add_auth_header': 'true'};

APIClient({
Dio? dio,
CustomInterceptor? customInterceptor,
}) {
_dio = dio ??
Dio(BaseOptions(
receiveTimeout: _defaultTimeout, connectTimeout: _defaultTimeout));

// if (kDebugMode) {
//   rootBundle.loadString('assets/certs/dev-certs.pem').then((data) {
//     // final bytes = utf8.encode(data);
//     // final securityContext = SecurityContext(withTrustedRoots: true)
//     //   ..setTrustedCertificatesBytes(bytes);
//     final securityContext = SecurityContext(withTrustedRoots: true);
//     _client = client ?? HttpClient(context: securityContext);

//     (_dio!.httpClientAdapter as DefaultHttpClientAdapter)
//         .onHttpClientCreate = (_) => _client;
//   });
// }

_dio!.interceptors.add(customInterceptor ?? CustomInterceptor());

}

Future<Map<String, dynamic>> get(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

try {
  return await _dio!
      .get<dynamic>(
        requestObject.getPath(),
        options: Options(
          headers: requestObject.headers ?? {},
          sendTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
          receiveTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        ),
        queryParameters: requestObject.queryParameters ?? {},
      )
      .then(processResponse);
} on DioError catch (e) {
  final fullPath = e.requestOptions.uri.path;
  final path = fullPath.split('/').skip(2).join('/');
  // If path starts with /, add it back
  final cleanPath = path.startsWith('/') ? path : '/$path';
  // Check if this is the endpoint to skip
  print('checkCleanPath $cleanPath');
  // Define this at the top of your get method or as a class-level constant
  final List<String> skipErrorHandlingGetEndpoints = [
    URIConstants.getUserByEmailId
  ];

  // Then use it like this:
  if (skipErrorHandlingGetEndpoints.contains(cleanPath)) {
    // Rethrow the exception to handle it from where endpoint was being called
    rethrow;
  }

  // final List<String> skipFlushbarGetEndpoints = [URIConstants.addFCMTokenByEmail];

  // final bool skipFlushbar = skipFlushbarGetEndpoints.contains(cleanPath);

  const bool skipFlushbar = false;

  // Handle DioError based on status code
  if (e.response != null) {
    final statusCode = e.response!.statusCode;
    
    switch (statusCode) {
      case 400:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Bad Request: Missing or invalid parameters'}'
        );
        }
        throw Exception('Bad Request: Missing or invalid parameters');
      
      case 403:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Forbidden: Your email is not authorized to access this resource'}'
        );
        }
        throw Exception('Forbidden: Your email is not authorized to access this resource');
      
      case 404:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Not Found: The requested data was not found in the database'}'
        );
      }
        throw Exception('Not Found: The requested data was not found in the database');
      
      case 500:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Internal Server Error: Something went wrong on the server'}'
        );
      }
        throw Exception('Internal Server Error: Something went wrong on the server');
      
      default:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Request failed'}'
        );
      }
        throw Exception('Request failed with status: $statusCode');
    }
  } else {
    // Handle errors without response (network errors, timeouts, etc.)
    if (e.type == DioErrorType.connectTimeout ||
        e.type == DioErrorType.receiveTimeout) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection timeout: Please check your internet connection'
      );
      throw Exception('Connection timeout: Please check your internet connection');
    } else if (e.type == DioErrorType.other) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection error: Unable to connect to the server'
      );
      throw Exception('Connection error: Unable to connect to the server');
    } else {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Network error: ${e.message}'
      );
      throw Exception('Network error: ${e.message}');
    }
  }

} catch (e) {
  // Handle any other unexpected errors (but don't catch our own thrown Exceptions)
  if (e is Exception && e.toString().contains('Exception:')) {
    // Re-throw our own exceptions
    rethrow;
  }
  await FlushbarUtils.show(
    messageType: MessageType.error,
    'An unexpected error occurred: ${e.toString()}'
  );
  throw Exception('An unexpected error occurred: ${e.toString()}');
}

}

Future<bool> getFlag(RequestObject requestObject,
  {bool protected = false}) async {
if (protected) {
  requestObject.headers?.addAll(_addAuthHeader);
}

return _dio!
    .get<dynamic>(
      requestObject.getPath(),
      options: Options(
        headers: requestObject.headers ?? {},
        sendTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        receiveTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      ),
      queryParameters: requestObject.queryParameters ?? {},
    )
    .then(processFlagResponse);

}

Future<Response<List>> getBytes(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

return _dio!.get<List<int>>(
  requestObject.getPath(),
  options: Options(
      headers: requestObject.headers ?? {},
      sendTimeout: requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      receiveTimeout:
          requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      responseType: ResponseType.bytes,
      followRedirects: false,
      validateStatus: (status) {
        return status == 200;
      }),
);

}

Future<Map<String, dynamic>> postMultiPartFile(RequestObject requestObject, {bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

dynamic dataToSend = requestObject.payload;

if (dataToSend is Map<String, dynamic> && dataToSend.containsKey('file') && dataToSend['file'] is File) {
  final File file = dataToSend['file'];
  final String fileName = file.path.split('/').last;

  final FormData formData = FormData.fromMap({
    ...dataToSend..remove('file'),
    'file': await MultipartFile.fromFile(file.path, filename: fileName),
  });

  dataToSend = formData;
}

return _dio!
    .post<dynamic>(
      requestObject.getPath(),
      data: dataToSend,
      options: Options(
        headers: requestObject.headers ?? {},
        sendTimeout: requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        receiveTimeout: requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      ),
    )
    .then(processResponse);

}

Future<Map<String, dynamic>> post(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

try {
  return await _dio!
      .post<dynamic>(
        requestObject.getPath(),
        data: requestObject.payload,
        options: Options(
          headers: requestObject.headers ?? {},
          sendTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
          receiveTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        ),
      )
      .then(processResponse);
} on DioError catch (e) {
  final fullPath = e.requestOptions.uri.path;
  final path = fullPath.split('/').skip(2).join('/');
  // If path starts with /, add it back
  final cleanPath = path.startsWith('/') ? path : '/$path';
  
  // Define this at the top of your get method or as a class-level constant
  final List<String> skipErrorHandlingPostEndpoints = [
    URIConstants.evaluation
  ];

  // Then use it like this:
  if (skipErrorHandlingPostEndpoints.contains(cleanPath)) {
    // Rethrow the exception to handle it from where endpoint was being called
    rethrow;
  }

  // final List<String> skipFlushbarPostEndpoints = [URIConstants.addFCMTokenByEmail];

  // final bool skipFlushbar = skipFlushbarPostEndpoints.contains(cleanPath);

  const bool skipFlushbar = false;

  // Handle DioError based on status code
  if (e.response != null) {
    final statusCode = e.response!.statusCode;
    
    switch (statusCode) {
      case 400:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Bad Request: Missing or invalid parameters'}'
        );
        }
        throw Exception('Bad Request: Missing or invalid parameters');
      
      case 403:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Forbidden: Your email is not authorized to access this resource'}'
        );
        }
        throw Exception('Forbidden: Your email is not authorized to access this resource');
      
      case 404:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Not Found: The requested data was not found in the database'}'
        );
      }
        throw Exception('Not Found: The requested data was not found in the database');
      
      case 500:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Internal Server Error: Something went wrong on the server'}'
        );
      }
        throw Exception('Internal Server Error: Something went wrong on the server');
      
      default:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Request failed'}'
        );
      }
        throw Exception('Request failed with status: $statusCode');
    }
  } else {
    // Handle errors without response (network errors, timeouts, etc.)
    if (e.type == DioErrorType.connectTimeout ||
        e.type == DioErrorType.receiveTimeout) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection timeout: Please check your internet connection'
      );
      throw Exception('Connection timeout: Please check your internet connection');
    } else if (e.type == DioErrorType.other) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection error: Unable to connect to the server'
      );
      throw Exception('Connection error: Unable to connect to the server');
    } else {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Network error: ${e.message}'
      );
      throw Exception('Network error: ${e.message}');
    }
  }
} catch (e) {
  // Handle any other unexpected errors (but don't catch our own thrown Exceptions)
  if (e is Exception && e.toString().contains('Exception:')) {
    // Re-throw our own exceptions
    rethrow;
  }
  await FlushbarUtils.show(
    messageType: MessageType.error,
    'An unexpected error occurred: ${e.toString()}'
  );
  throw Exception('An unexpected error occurred: ${e.toString()}');
}

}

Future<Map<String, dynamic>> postFormData(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

return _dio!
    .post<dynamic>(
      requestObject.getPath(),
      data: requestObject.rawPayload,
      options: Options(
        headers: requestObject.headers,
        sendTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        receiveTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      ),
    )
    .then(processResponse);

}

Future<Map<String, dynamic>> put(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

try {
  return await _dio!
      .put<dynamic>(
        requestObject.getPath(),
        data: requestObject.payload,
        options: Options(
          headers: requestObject.headers ?? {},
          sendTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
          receiveTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        ),
      )
      .then(processResponse);
} on DioError catch (e) {
  final fullPath = e.requestOptions.uri.path;
  final path = fullPath.split('/').skip(2).join('/');
  // If path starts with /, add it back
  final cleanPath = path.startsWith('/') ? path : '/$path';
  
  // Define this at the top of your get method or as a class-level constant
  final List<String> skipErrorHandlingPutEndpoints = [
    URIConstants.updateCart
  ];

  // Then use it like this:
  if (skipErrorHandlingPutEndpoints.contains(cleanPath)) {
    // Rethrow the exception to handle it from where endpoint was being called
    rethrow;
  }

  final List<String> skipFlushbarPutEndpoints = [URIConstants.addFCMTokenByEmail];

  final bool skipFlushbar = skipFlushbarPutEndpoints.contains(cleanPath);
  
  // Handle DioError based on status code
  if (e.response != null) {
    final statusCode = e.response!.statusCode;
    
    switch (statusCode) {
      case 400:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Bad Request: Missing or invalid parameters'}'
        );
        }
        throw Exception('Bad Request: Missing or invalid parameters');
      
      case 403:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Forbidden: Your email is not authorized to access this resource'}'
        );
        }
        throw Exception('Forbidden: Your email is not authorized to access this resource');
      
      case 404:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Not Found: The requested data was not found in the database'}'
        );
      }
        throw Exception('Not Found: The requested data was not found in the database');
      
      case 500:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Internal Server Error: Something went wrong on the server'}'
        );
      }
        throw Exception('Internal Server Error: Something went wrong on the server');
      
      default:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Request failed'}'
        );
      }
        throw Exception('Request failed with status: $statusCode');
    }
  } else {
    // Handle errors without response (network errors, timeouts, etc.)
    if (e.type == DioErrorType.connectTimeout ||
        e.type == DioErrorType.receiveTimeout) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection timeout: Please check your internet connection'
      );
      throw Exception('Connection timeout: Please check your internet connection');
    } else if (e.type == DioErrorType.other) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection error: Unable to connect to the server'
      );
      throw Exception('Connection error: Unable to connect to the server');
    } else {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Network error: ${e.message}'
      );
      throw Exception('Network error: ${e.message}');
    }
  }
} catch (e) {
  // Handle any other unexpected errors (but don't catch our own thrown Exceptions)
  if (e is Exception && e.toString().contains('Exception:')) {
    // Re-throw our own exceptions
    rethrow;
  }
  await FlushbarUtils.show(
    messageType: MessageType.error,
    'An unexpected error occurred: ${e.toString()}'
  );
  throw Exception('An unexpected error occurred: ${e.toString()}');
}

}

Future<Map<String, dynamic>> patch(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

return _dio!
    .patch<dynamic>(
      requestObject.getPath(),
      data: requestObject.payload,
      options: Options(
        headers: requestObject.headers ?? {},
        sendTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        receiveTimeout:
            requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
      ),
    )
    .then(processResponse);

}

Future<Map<String, dynamic>> delete(RequestObject requestObject,
{bool protected = false}) async {
if (protected) {
requestObject.headers?.addAll(_addAuthHeader);
}

try {
  return await _dio!
      .delete<dynamic>(
        requestObject.getPath(),
        data: requestObject.payload,
        options: Options(
          headers: requestObject.headers ?? {},
          sendTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
          receiveTimeout:
              requestObject.timeout?.inMilliseconds ?? _defaultTimeout,
        ),
      )
      .then(processResponse);
} on DioError catch (e) {
  final fullPath = e.requestOptions.uri.path;
  final path = fullPath.split('/').skip(2).join('/');
  // If path starts with /, add it back
  final cleanPath = path.startsWith('/') ? path : '/$path';
  
  // Define this at the top of your get method or as a class-level constant
  final List<String> skipErrorHandlingDeleteEndpoints = [
    URIConstants.deleteUserAccount
  ];

  // Then use it like this:
  if (skipErrorHandlingDeleteEndpoints.contains(cleanPath)) {
    // Rethrow the exception to handle it from where endpoint was being called
    rethrow;
  }

  // final List<String> skipFlushbarDeleteEndpoints = [URIConstants.addFCMTokenByEmail];

  // final bool skipFlushbar = skipFlushbarDeleteEndpoints.contains(cleanPath);

  const bool skipFlushbar = false;

  // Handle DioError based on status code
  if (e.response != null) {
    final statusCode = e.response!.statusCode;
    
    switch (statusCode) {
      case 400:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Bad Request: Missing or invalid parameters'}'
        );
        }
        throw Exception('Bad Request: Missing or invalid parameters');
      
      case 403:
        if(!skipFlushbar) {
          await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Forbidden: Your email is not authorized to access this resource'}'
        );
        }
        throw Exception('Forbidden: Your email is not authorized to access this resource');
      
      case 404:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Not Found: The requested data was not found in the database'}'
        );
      }
        throw Exception('Not Found: The requested data was not found in the database');
      
      case 500:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Internal Server Error: Something went wrong on the server'}'
        );
      }
        throw Exception('Internal Server Error: Something went wrong on the server');
      
      default:
      if(!skipFlushbar) {
        await FlushbarUtils.show(
          messageType: MessageType.error,
          '$cleanPath : $statusCode ${e.response!.statusMessage ?? 'Request failed'}'
        );
      }
        throw Exception('Request failed with status: $statusCode');
    }
  } else {
    // Handle errors without response (network errors, timeouts, etc.)
    if (e.type == DioErrorType.connectTimeout ||
        e.type == DioErrorType.receiveTimeout) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection timeout: Please check your internet connection'
      );
      throw Exception('Connection timeout: Please check your internet connection');
    } else if (e.type == DioErrorType.other) {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Connection error: Unable to connect to the server'
      );
      throw Exception('Connection error: Unable to connect to the server');
    } else {
      await FlushbarUtils.show(
        messageType: MessageType.error,
        'Network error: ${e.message}'
      );
      throw Exception('Network error: ${e.message}');
    }
  }
} catch (e) {
  // Handle any other unexpected errors (but don't catch our own thrown Exceptions)
  if (e is Exception && e.toString().contains('Exception:')) {
    // Re-throw our own exceptions
    rethrow;
  }
  await FlushbarUtils.show(
    messageType: MessageType.error,
    'An unexpected error occurred: ${e.toString()}'
  );
  throw Exception('An unexpected error occurred: ${e.toString()}');
}

}

Map<String, dynamic> processResponse(Response response) {
if (response.data == '' || response.data == null) {
return <String, dynamic>{'statusCode': response.statusCode};
} else {
if (response.data is List) {
return <String, dynamic>{'data': response.data};
} else if (response.data is String) {
return <String, dynamic>{'data': response.data};
} else {
return response.data as Map<String, dynamic>;
}
}
}

bool processFlagResponse(Response response) {
if (response.data == '' || response.data == null) {
return false;
} else {
if (response.data is bool) {
return response.data;
} else {
return false;
}
}
}
}

This is my CustomInterceptor.dart
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

class CustomInterceptor extends Interceptor {
@OverRide
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (kDebugMode) {
debugPrint('REQUEST[${options.method}] => PATH: ${options.path}');
}

return super.onRequest(options, handler);

}

@OverRide
void onResponse(
Response response, ResponseInterceptorHandler handler) {
if (kDebugMode) {
debugPrint(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
}
return super.onResponse(response, handler);
}

@OverRide
void onError(DioError err, ErrorInterceptorHandler handler) {
if (kDebugMode) {
debugPrint(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
}
return super.onError(err, handler);
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions