From 88d430bb863ff874745d87c33382f593a897f473 Mon Sep 17 00:00:00 2001 From: arafaysaleem Date: Sun, 13 Jun 2021 15:37:44 -0700 Subject: [PATCH] docs(Services): Add documentation for all interceptors Signed-off-by: arafaysaleem --- .../interceptors/api_interceptor.dart | 47 +++++++++++++ .../interceptors/logging_interceptor.dart | 69 +++++++++++++++++-- .../refresh_token_interceptor.dart | 24 +++++++ 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/lib/services/networking/interceptors/api_interceptor.dart b/lib/services/networking/interceptors/api_interceptor.dart index 0f11961..d7f95bd 100644 --- a/lib/services/networking/interceptors/api_interceptor.dart +++ b/lib/services/networking/interceptors/api_interceptor.dart @@ -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, @@ -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, diff --git a/lib/services/networking/interceptors/logging_interceptor.dart b/lib/services/networking/interceptors/logging_interceptor.dart index 0ec5a7d..678cb0e 100644 --- a/lib/services/networking/interceptors/logging_interceptor.dart +++ b/lib/services/networking/interceptors/logging_interceptor.dart @@ -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, @@ -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, @@ -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, @@ -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 headers = dioError.response!.data["headers"]; - String message = headers["message"]; - String error = headers["error"]; + final Map 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 data = headers["data"]; if(data.isNotEmpty) { debugPrint("\tData: $data"); diff --git a/lib/services/networking/interceptors/refresh_token_interceptor.dart b/lib/services/networking/interceptors/refresh_token_interceptor.dart index 8e55a5d..c6aa86a 100644 --- a/lib/services/networking/interceptors/refresh_token_interceptor.dart +++ b/lib/services/networking/interceptors/refresh_token_interceptor.dart @@ -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, @@ -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 _refreshTokenRequest({ required DioError dioError, required ErrorInterceptorHandler handler,