Skip to content

Creating own dio Intercepor

Why create a Dio Interceptor?

An interceptor is a centralized place to observe and modify every request/response/error that goes through Dio. Instead of repeating the same logic in every API call, you put it once in an interceptor.

Typical reasons:

  • Add auth headers (e.g., bearer token) automatically. If you directly put token while initalizing the dio in it’s header, it will take token through out the session, sometime token might change in middle because of refresh token, or cause of other reason, interceptor lets you read the latest token easily.
  • Standardize logging (request/response debugging).
  • Handle common errors (401 β†’ logout/refresh token, 500 β†’ show generic message).
  • Normalize responses (wrap/unwrap backend formats, map status codes).
  • Apply retries or connectivity checks in one place.

Creating your own Dio interceptor

Dio gives you Interceptor with three hooks:

  • onRequest: runs before the request is sent.
  • onResponse: runs when a response is received successfully.
  • onError: runs when the request fails (timeouts, 4xx/5xx, no internet, etc.).

You can implement your own interceptor by extending Interceptor and attaching it to Dio.

dart

import 'package:dio/dio.dart';
class AppInterceptor extends Interceptor {
AppInterceptor({
required this.tokenProvider,
required this.onUnauthorized,
});
final Future<String?> Function() tokenProvider;
final void Function() onUnauthorized;
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
// Attach headers / auth token globally
final token = await tokenProvider();
if (token != null && token.isNotEmpty) {
options.headers['Authorization'] = 'Bearer $token';
}
// Example: enforce JSON headers in one place
options.headers['Accept'] = 'application/json';
return handler.next(options); // continue
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// Light touch: you can inspect/transform data here if needed
return handler.next(response); // continue
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
// Centralized error handling (mapping / side effects)
final statusCode = err.response?.statusCode;
if (statusCode == 401) {
// Token expired / invalid
onUnauthorized();
}
return handler.next(err); // pass error forward
}
}

Attach it to your Dio instance:

dart

final dio = Dio(
BaseOptions(
baseUrl: 'https://api.yourdomain.com',
connectTimeout: const Duration(seconds: 15),
receiveTimeout: const Duration(seconds: 15),
),
);
dio.interceptors.add(
AppInterceptor(
tokenProvider: () async => /* read from secure storage */,
onUnauthorized: () {
// e.g., clear session + navigate to login
},
),
);