How to Debug Network Requests in Flutter with HTTP Interceptor

Learn how to debug network requests in Flutter using HTTP interceptor and see how Requestly offers a simpler alternative to inspect, modify, and mock API calls without changing the code.

Guide Banner Image
Home Guide How to Debug Network Requests in Flutter with HTTP Interceptor

How to Debug Network Requests in Flutter with HTTP Interceptor

When building Flutter apps, you often need to manage network requests to fetch or send data through APIs. Debugging these network requests is crucial to identify issues like incorrect endpoints, missing headers, or unexpected responses. Developers commonly use HTTP interceptors to inspect and log network traffic directly in their code.

This article explains how to use Flutter HTTP interceptors to debug network requests. It covers setup, implementation, and the challenges.

What Are HTTP Interceptors in Flutter?

In Flutter, an HTTP interceptor is a component that allows you to inspect, modify, or log network requests and responses. You can use it to add headers, track requests, retry failed calls, or block specific requests.

The core http package doesn’t have built‑in interceptor support, so you need to implement this behavior by extending http.BaseClient or a plugin like http_interceptor. If you use Dio, interceptors are built in, making it easy to add this functionality to your app.

Setting Up HTTP Interceptor in Flutter

Before using a Flutter HTTP interceptor to debug network requests, you must set up the right package and configure it correctly in your app.

Prerequisites

  • A Flutter app that makes HTTP or API requests
  • Familiarity with the HTTP package or the Dio package for making API requests.

1. Add Dependencies

You need to add the required packages to your pubspec.yaml file. For example, if you are using the http_interceptor package:

dependencies:

  http: ^0.14.0

  http_interceptor: ^1.0.1



Run flutter pub get to install the packages.

If you are using Dio, the setup is similar:




dependencies:

  dio: ^5.3.1

2. Create an Interceptor

You must define a class that implements the interceptor logic. This is where you will add logging and inspection code.

For http_interceptor:

import 'package:http_interceptor/http_interceptor.dart';



class LoggingInterceptor implements InterceptorContract {

  @override

  Future<RequestData> interceptRequest({required RequestData data}) async {

    print("Request to: ${data.url}");

    print("Headers: ${data.headers}");

    print("Body: ${data.body}");

    return data;

  }




  @override

  Future<ResponseData> interceptResponse({required ResponseData data}) async {

    print("Response status: ${data.statusCode}");

    print("Response body: ${data.body}");

    return data;

  }

}

For Dio:

import 'package:dio/dio.dart';



class LoggingInterceptor extends Interceptor {

  @override

  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {

    print("Request to: ${options.uri}");

    print("Headers: ${options.headers}");

    print("Body: ${options.data}");

    handler.next(options);

  }




  @override

  void onResponse(Response response, ResponseInterceptorHandler handler) {

    print("Response status: ${response.statusCode}");

    print("Response body: ${response.data}");

    handler.next(response);

  }




  @override

  void onError(DioError err, ErrorInterceptorHandler handler) {

    print("Error: ${err.message}");

    handler.next(err);

  }

}

3. Set Up the HTTP Client with Interceptors

You need to create a client that uses your interceptor.

For http_interceptor:

import 'package:http/http.dart';

import 'package:http_interceptor/http_interceptor.dart';




final client = InterceptedClient.build(interceptors: [LoggingInterceptor()]);

For Dio:

final dio = Dio();

dio.interceptors.add(LoggingInterceptor());

4. Use the Intercepted HTTP Client

You can now use this client to make requests, and the interceptor will handle logging and inspection automatically.

Example for http_interceptor:

final response = await client.get(Uri.parse("https://jsonplaceholder.typicode.com/posts/1"));

print("Fetched data: ${response.body}");

Example for Dio:

final response = await dio.get("https://jsonplaceholder.typicode.com/posts/1");

print("Fetched data: ${response.data}");

5. Run and Test

Run your app and trigger the API calls. You will see the request and response details printed in the console. This helps you verify the data sent to and received from the API.

How to Debug Network Requests in Flutter Using HTTP Interceptor

To debug network requests using a Flutter HTTP interceptor, you need to capture and log all the essential details of each API call your app makes.

The goal is to check if the request is built correctly and sent to the correct URL, and if the response from the server is what you expect. This helps you catch issues like wrong endpoints, missing headers, or bad data before they affect your app’s behavior.

You should log:

  • The full request URL to see the exact API endpoint and query parameters being called
  • The request headers to verify that required headers like authentication tokens or content types are included
  • The request body to check the data being sent, especially for POST or PUT requests
  • The response status code to confirm if the API call succeeded or failed
  • The response headers and body to inspect the returned data and ensure it matches what your app expects
  • Any errors, including their messages, to see what went wrong during the network call

Below is how you can implement this using http_interceptor:

import 'package:http_interceptor/http_interceptor.dart';




class FlutterHttpLoggingInterceptor implements InterceptorContract {

  @override

  Future<RequestData> interceptRequest({required RequestData data}) async {

    print("Request URL: ${data.url}");

    print("Request Headers: ${data.headers}");

    print("Request Body: ${data.body}");

    return data;

  }




  @override

  Future<ResponseData> interceptResponse({required ResponseData data}) async {

    print("Response Status: ${data.statusCode}");

    print("Response Headers: ${data.headers}");

    print("Response Body: ${data.body}");

    return data;

  }

}

If you are using dio, the setup looks like this:

import 'package:dio/dio.dart';




class FlutterHttpLoggingInterceptor extends Interceptor {

  @override

  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {

    print("Request URL: ${options.uri}");

    print("Request Headers: ${options.headers}");

    print("Request Body: ${options.data}");

    handler.next(options);

  }




  @override

  void onResponse(Response response, ResponseInterceptorHandler handler) {

    print("Response Status: ${response.statusCode}");

    print("Response Headers: ${response.headers}");

    print("Response Body: ${response.data}");

    handler.next(response);

  }




  @override

  void onError(DioError err, ErrorInterceptorHandler handler) {

    print("Request Error: ${err.message}");

    handler.next(err);

  }

}

You can add timing logic if you want to measure how long each API call takes. This helps identify slow requests that could affect app performance. Here is an example for dio:

class TimingInterceptor extends Interceptor {

  @override

  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {

    options.extra["startTime"] = DateTime.now();

    handler.next(options);

  }




  @override

  void onResponse(Response response, ResponseInterceptorHandler handler) {

    final startTime = response.requestOptions.extra["startTime"] as DateTime;

    final duration = DateTime.now().difference(startTime);

    print("Request to ${response.requestOptions.uri} took ${duration.inMilliseconds} ms");

    handler.next(response);

  }




  @override

  void onError(DioError err, ErrorInterceptorHandler handler) {

    final startTime = err.requestOptions.extra["startTime"] as DateTime;

    final duration = DateTime.now().difference(startTime);

    print("Failed request to ${err.requestOptions.uri} took ${duration.inMilliseconds} ms");

    print("Error: ${err.message}");

    handler.next(err);

  }

}

Limitations of Flutter HTTP Interceptors for Debugging

Flutter HTTP interceptors help log and inspect network requests, but they have several limitations that can slow down or complicate debugging. These limits become more noticeable as your app grows or you must test more complex scenarios.

  • Need for code changes: You must add or update interceptor code in your app to modify what gets logged or inspected. This means rebuilding the app each time you want to change the logging logic or inspect new parts of a request or response.
  • No UI to view network activity: The interceptor logs appear in the console. There is no built-in way to filter, search, or organize these logs, so finding the exact request or response you want to inspect becomes harder, especially in apps with many API calls.
  • Cannot modify or mock requests on the fly: Interceptors let you log and modify requests through code, but you cannot change request URLs, headers, or bodies at runtime without writing and deploying code changes. This makes it hard to test alternate API responses or simulate edge cases.
  • Hard to share debug setup: The interceptor logic lives inside your app code. If you want other developers or testers to use the same setup, they need to copy or merge the code. There is no easy way to share and apply logging rules across teams without duplicating effort.
  • No separation from app logic: The interceptor code runs as part of your app. This means any changes to logging or debugging logic can increase the risk of introducing bugs or making the app more challenging to maintain.

HTTP Interceptor Banner

Requestly: A Simpler Alternative for Debugging Network Requests

Requestly allows you to intercept network traffic outside of your app. It lets you inspect, modify, and mock HTTP requests and responses without writing or changing any code. You set up rules in a visual interface that apply to network calls made by your app.

Requestly can help debug network requests in several ways:

  • Inspect network traffic without code changes: Requestly shows all network requests in a UI where you can filter, search, and view full details. You need not modify or redeploy your app to see this data.
  • Modify requests: Requestly rules allow you to change request URLs, headers, or bodies. This lets you test different API conditions without touching your code.
  • Mock API responses: Requestly lets you simulate different API responses, including errors or specific payloads. This helps you test edge cases or build features even if the backend is not ready.
  • Share rules with your team: You can export and share Requestly rules, so other developers or testers can use the same debugging setup without duplicating effort.

Talk to an Expert

Conclusion

Flutter HTTP interceptors allow you to log and inspect network requests inside your app. They help track request URLs, headers, bodies, and responses so you can identify issues during development. However, they require code changes for each adjustment and offer limited control over how you view or manage network data.

Requestly offers a simpler alternative by letting you modify, mock, and inspect HTTP requests without changing your app code. You can create rules to log requests, change headers or bodies, simulate responses, or block requests in real time.

Try Requestly for Free

Tags
Automation Testing Mobile App Testing Testing Tools