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 }, ),);