network<T> method

Future<T?> network<T>({
  1. required dynamic request(
    1. Dio api
    ),
  2. dynamic handleSuccess(
    1. Response response
    )?,
  3. dynamic handleFailure(
    1. DioException error
    )?,
  4. String? bearerToken,
  5. String? baseUrl,
  6. bool useUndefinedResponse = true,
  7. bool shouldRetry = true,
  8. bool? shouldSetAuthHeaders,
  9. int? retry,
  10. Duration? retryDelay,
  11. bool retryIf(
    1. DioException dioException
    )?,
  12. Duration? connectionTimeout,
  13. Duration? receiveTimeout,
  14. Duration? sendTimeout,
  15. Duration? cacheDuration,
  16. String? cacheKey,
  17. Map<String, dynamic>? headers,
})

Networking class to handle API requests Use the request callback to call an API handleSuccess overrides the response on a successful status code handleFailure overrides the response on a failure

Usage: Future<List

Implementation

Future<T?> network<T>(
    {required Function(Dio api) request,
    Function(Response response)? handleSuccess,
    Function(DioException error)? handleFailure,
    String? bearerToken,
    String? baseUrl,
    bool useUndefinedResponse = true,
    bool shouldRetry = true,
    bool? shouldSetAuthHeaders,
    int? retry,
    Duration? retryDelay,
    bool Function(DioException dioException)? retryIf,
    Duration? connectionTimeout,
    Duration? receiveTimeout,
    Duration? sendTimeout,
    Duration? cacheDuration,
    String? cacheKey,
    Map<String, dynamic>? headers}) async {
  headers ??= {};
  try {
    Map<String, dynamic> oldHeader = _api.options.headers;
    Map<String, dynamic> newValuesToAddToHeader = {};
    if (headers.isNotEmpty) {
      for (var header in headers.entries) {
        if (!oldHeader.containsKey(header.key)) {
          newValuesToAddToHeader.addAll({header.key: header.value});
        }
      }
    }
    if (await shouldRefreshToken()) {
      await refreshToken(Dio());
    }

    if (bearerToken != null) {
      newValuesToAddToHeader.addAll({"Authorization": "Bearer $bearerToken"});
    } else {
      if ((shouldSetAuthHeaders ?? this.shouldSetAuthHeaders) == true) {
        newValuesToAddToHeader.addAll(await setAuthHeaders(headers));
      }
    }
    _api.options.headers.addAll(newValuesToAddToHeader);
    String oldBaseUrl = _api.options.baseUrl;
    if (baseUrl != null) {
      _api.options.baseUrl = baseUrl;
    }
    if (connectionTimeout != null) {
      _api.options.connectTimeout = connectionTimeout;
    }
    if (receiveTimeout != null) {
      _api.options.receiveTimeout = receiveTimeout;
    }
    if (sendTimeout != null) {
      _api.options.sendTimeout = sendTimeout;
    }

    Response? response;

    Duration? cacheDurationRequest = cacheDuration;
    cacheDurationRequest ??= _cacheDuration;

    String? cacheKeyRequest = cacheKey;
    cacheKeyRequest ??= _cacheKey;

    if (cacheDurationRequest != null || cacheKeyRequest != null) {
      assert(cacheDurationRequest != null, 'Cache duration is required');
      assert(cacheKeyRequest != null, 'Cache key is required');

      int inSeconds = cacheDurationRequest?.inSeconds ?? 60;
      bool cacheHit = true;
      Map responseMap = await ny_cache
          .cache()
          .saveRemember(cacheKeyRequest!, inSeconds, () async {
        cacheHit = false;
        Response requestData = await request(_api);
        return {
          'requestOptions': {
            'path': requestData.requestOptions.path,
            'method': requestData.requestOptions.method,
            'baseUrl': requestData.requestOptions.baseUrl,
          },
          'statusCode': requestData.statusCode,
          'statusMessage': requestData.statusMessage,
          'data': requestData.data,
        };
      });
      response = Response(
        requestOptions: RequestOptions(
          path: responseMap['requestOptions']['path'],
          method: responseMap['requestOptions']['method'],
          baseUrl: responseMap['requestOptions']['baseUrl'],
        ),
        statusCode: responseMap['statusCode'],
        statusMessage: responseMap['statusMessage'],
        data: responseMap['data'],
      );

      if (cacheHit) {
        printDebug('');
        printDebug('╔╣ ${response.requestOptions.uri}');
        printDebug('║  Cache ${cacheHit ? 'hit' : 'miss'}: $cacheKeyRequest');
        printDebug('║  Status: ${response.statusCode}');
        printDebug('╚╣ Response');
        printDebug(response.data);
      } else {
        printDebug('Cached response $cacheKeyRequest');
      }
    } else {
      response = await request(_api);
    }

    _api.options.headers = oldHeader; // reset headers
    _api.options.baseUrl = oldBaseUrl; //  reset base url
    _api.options.queryParameters = {}; // reset query parameters

    dynamic data = handleResponse<T>(response!, handleSuccess: handleSuccess);
    if (data != T && useUndefinedResponse) {
      onUndefinedResponse(data, response, _context);
    }
    if (_onSuccessEvent != null) {
      _onSuccessEvent!(response, data);
    }
    _context = null;
    return data;
  } on DioException catch (dioException) {
    int nyRetries = retry ?? this.retry;
    Duration nyRetryDelay = retryDelay ?? this.retryDelay;
    bool Function(DioException dioException)? retryIfFinal = this.retryIf;
    if (retryIf != null) {
      retryIfFinal = retryIf;
    }
    if (retryIfFinal != null) {
      shouldRetry = retryIfFinal(dioException);
    }
    if (_retrying == false && shouldRetry == true && nyRetries > 0) {
      _retrying = true;
      for (var i = 0; i < nyRetries; i++) {
        await Future.delayed(nyRetryDelay);
        NyLogger.debug("[${i + 1}] Retrying request...");
        dynamic response = await network(
          request: request,
          handleSuccess: handleSuccess,
          handleFailure: handleFailure,
          bearerToken: bearerToken,
          baseUrl: baseUrl,
          useUndefinedResponse: useUndefinedResponse,
          headers: headers,
          shouldRetry: false,
        );
        if (response != null) {
          _retrying = false;
          return response;
        }
      }
      _retrying = false;
    }

    NyLogger.error(dioException.toString());
    error(dioException);
    if (_context != null) {
      displayError(dioException, _context!);
    }

    if (handleFailure != null) {
      return handleFailure(dioException);
    }

    if (_onErrorEvent != null) {
      _onErrorEvent!(dioException);
    }

    return null;
  } on Exception catch (e) {
    NyLogger.error(e.toString());
    return null;
  }
}