fetch<Success> function

Future<Response<Success>> fetch<Success>(
  1. Request<Success> req, {
  2. Dio? dio,
  3. CancelToken? cancelToken,
  4. ProgressCallback? onSendProgress,
  5. ProgressCallback? onReceiveProgress,
})

Implementation

Future<Response<Success>> fetch<Success>(
  Request<Success> req, {
  dio_package.Dio? dio,
  dio_package.CancelToken? cancelToken,
  dio_package.ProgressCallback? onSendProgress,
  dio_package.ProgressCallback? onReceiveProgress,
}) async {
  int startAgainLimit = 10;
  while (startAgainLimit > 0) {
    Response? res;
    int limit;

    RequestInterceptor<dynamic>? requestInterceptor = req.requestInterceptor;
    limit = 10;
    while (limit > 0 && requestInterceptor != null) {
      try {
        RequestInterceptorFlow flow = await requestInterceptor.interceptor.call(req);
        if (flow.terminate) {
          res = flow.response!;
        }
        req = flow.request as Request<Success>;
        requestInterceptor = requestInterceptor.next;
      } on ResponseCustomError catch (e) {
        return ResponseCustomError(
          message: e.message,
          body: e.body,
          error: e.error,
          statusCode: e.statusCode,
          headers: e.headers,
        );
      }
      limit--;
    }

    if (res == null) {
      int id = _requestRunningId++;
      String url = req.isIncludeBaseUrl == true ? '${req.baseUrl}${req.url}' : '${req.url}';

      final queryParamsString = req.queryParametersString;
      final fullUrl = url.contains('?') ? '$url&$queryParamsString' : '$url?$queryParamsString';

      sysLog.i('($id) >>> network request: [${req.method}] $fullUrl\n'
          '        body: ${req.body}\n'
          '        headers: ${req.headers}');

      dio ??= dio_package.Dio();
      cancelToken ??= dio_package.CancelToken();

      try {
        dio_package.Response<String> dioResponse = await dio.request<String>(
          fullUrl,
          data: req.body?.getBody(),
          options: dio_package.Options(
            method: req.method,
            headers: req.headers,
            validateStatus: (int? status) => status != null,
          ),
          cancelToken: cancelToken,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
        );

        res = Response<String>(
          data: dioResponse.data,
          body: dioResponse.data,
          statusCode: dioResponse.statusCode ?? 0,
          headers: dioResponse.headers.map,
        );
      } on dio_package.DioError catch (e) {
        cancelToken.cancel();
        res = _getResponseByDioError(e);
      }

      sysLog.i('($id) <<< network response: statusCode=${res.statusCode}\n'
          '        header: ${res.headers}\n'
          '        body: ${res.body}\n');
    }

    ResponseInterceptor<dynamic>? responseInterceptor = req.responseInterceptor;
    limit = 10;
    bool startAgain = false;
    while (limit > 0 && responseInterceptor != null) {
      try {
        var responseFlow = await responseInterceptor.interceptor(res!);
        if (responseFlow.terminate) {
          var r = Response.copyWith<Success>(
            responseFlow.response,
            message: responseFlow.response.message,
            body: responseFlow.response.body,
            statusCode: responseFlow.response.statusCode,
            headers: responseFlow.response.headers,
            data: responseFlow.response.data,
            error: responseFlow.response.error,
            extra: responseFlow.response.extra,
          );
          return r;
        }
        if (responseFlow.requestDecorator != null) {
          req = responseFlow.requestDecorator!.call(req) as Request<Success>;
        }
        if (responseFlow.startAgain) {
          startAgain = true;
          break;
        }
        res = responseFlow.response;
        responseInterceptor = responseInterceptor.next;
      } on ResponseCustomError catch (r) {
        return Response.copyWith<Success>(
          r,
          message: r.message,
          body: r.body,
          error: r.error,
          extra: r.extra,
          statusCode: r.statusCode,
          headers: r.headers,
        );
      }
      limit--;
    }

    if (startAgain) {
      startAgainLimit--;
      continue;
    }

    if (res == null) throw StateError('response is null state');

    try {
      Response<Success> finalResponse = Response.copyWith<Success>(
        res,
        message: res.message,
        body: res.body,
        data: req.mappingResponse?.call(res.data, res) ?? res.data,
        error: res.error,
        extra: res.extra,
        statusCode: res.statusCode,
        headers: res.headers,
      );
      return finalResponse;
    } on ResponseCustomError catch (e) {
      return ResponseCustomError(
        message: e.message,
        body: e.body,
        error: e.error,
        extra: e.extra,
        statusCode: e.statusCode,
        headers: e.headers,
      );
    } catch (e, s) {
      String errorMessage = 'network response mapping fail: cannot parse "${res.data}" to model "$Success"';
      sysLog.w(errorMessage);
      return ResponseMappingFail(
        message: errorMessage,
        body: res.body,
        error: res.error,
        extra: res.extra,
        statusCode: res.statusCode,
        headers: res.headers,
      );
    }
  }
  throw Exception('startAgainLimit');
}