Skip to content

Commit

Permalink
docs(Services): Add documentation for all interceptors
Browse files Browse the repository at this point in the history
Signed-off-by: arafaysaleem <a.rafaysaleem@gmail.com>
  • Loading branch information
arafaysaleem committed Jun 13, 2021
1 parent b3862ea commit 88d430b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 4 deletions.
47 changes: 47 additions & 0 deletions lib/services/networking/interceptors/api_interceptor.dart
Expand Up @@ -3,7 +3,29 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../../../providers/all_providers.dart';

/// A class that holds intercepting logic for API related requests. This is
/// the first interceptor in case of both request and response.
///
/// Since this interceptor isn't responsible for error handling, if an exception
/// occurs it is passed on the next [Interceptor] or to [Dio].
class ApiInterceptor 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 inject any token/API keys in the request.
///
/// 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,
Expand All @@ -20,6 +42,31 @@ class ApiInterceptor extends Interceptor {
return handler.next(options);
}

/// 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 check the success of the response by verifying
/// its headers.
///
/// If response is successful, it is simply passed on. It may again be
/// intercepted if there are any after it. If none, it is passed to [Dio].
///
/// Else if response indicates failure, a [DioError] is thrown with the
/// response and original request's options.
///
/// ** The success criteria 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 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,
Expand Down
69 changes: 65 additions & 4 deletions lib/services/networking/interceptors/logging_interceptor.dart
Expand Up @@ -4,8 +4,30 @@ import 'package:flutter/foundation.dart';

import 'package:dio/dio.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. **
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,
Expand Down Expand Up @@ -33,6 +55,23 @@ class LoggingInterceptor extends Interceptor {
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,
Expand All @@ -50,6 +89,28 @@ class LoggingInterceptor extends Interceptor {
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,
Expand All @@ -59,12 +120,12 @@ class LoggingInterceptor extends Interceptor {
if(dioError.response != null){
debugPrint("\tStatus code: ${dioError.response!.statusCode}");
if(dioError.response!.data != null){
final Map<String,dynamic> headers = dioError.response!.data["headers"];
String message = headers["message"];
String error = headers["error"];
final Map<String,dynamic> headers = dioError.response!.data["headers"]; //API Dependant
String message = headers["message"]; //API Dependant
String error = headers["error"]; //API Dependant
debugPrint("\tException: $error");
debugPrint("\tMessage: $message");
if(headers.containsKey("data")){
if(headers.containsKey("data")){ //API Dependant
List<dynamic> data = headers["data"];
if(data.isNotEmpty) {
debugPrint("\tData: $data");
Expand Down
Expand Up @@ -8,14 +8,33 @@ import '../../../providers/all_providers.dart';
//Endpoints
import '../api_endpoint.dart';

/// A class that holds intercepting logic for refreshing tokens. This is
/// the last interceptor in the queue.
class RefreshTokenInterceptor extends Interceptor {

/// An instance of [Dio] for network requests
final Dio _dio;

RefreshTokenInterceptor(this._dio);

/// The name of the exception on which this interceptor is triggered.
// ignore: non_constant_identifier_names
String get TokenExpiredException => "TokenExpiredException";

/// This method is used to send a refresh token request if the error
/// indicates an expired token.
///
/// In case of expired token, it creates a new [Dio] instance, replicates
/// its options and locks the current instance to prevent further requests.
/// The new instance retrieves a new token and updates it. The original
/// request is retried with the new token.
///
/// ** NOTE: ** Any requests from original instance will trigger all attached
/// interceptors as expected.
///
/// ** The structure of response in case of errors or the refresh request is
/// dependant on the API and may not always be the same. It might need
/// changing according to your own API. **
@override
void onError(
DioError dioError,
Expand Down Expand Up @@ -75,6 +94,11 @@ class RefreshTokenInterceptor extends Interceptor {
return super.onError(dioError, handler);
}

/// This method sends out a request to refresh the token. Since this request
/// uses the new [Dio] instance it needs its own logging and error handling.
///
/// ** The structure of response is dependant on the API and may not always
/// be the same. It might need changing according to your own API. **
Future<String?> _refreshTokenRequest({
required DioError dioError,
required ErrorInterceptorHandler handler,
Expand Down

0 comments on commit 88d430b

Please sign in to comment.