wrapAndHandleHttpRequestResponse<T> method

  1. @override
Future<Either<Failure, T>> wrapAndHandleHttpRequestResponse<T>(
  1. Future<Response> futureResponse(), {
  2. required DataOrFailureHandleResponse<T> onResponse,
  3. DataOrFailureHandleException<T>? onError,
  4. List<int> successStatuses = const [200, 201, 202, 203, 204],
  5. bool debugRequestBody = true,
})
inherited

Provides you with an easy way to handle common Http API request This helper will help you with some boilerplate needed when implementing handling http request following our architecture futureResponse its commonly the return type of a HttpClient in most of its methods (get, post, patch, put, etc)

onResponse is required in order for you to process your server's custom response and return the value you need, this callback is triggered only if the response status code returned by the server is part of the successStatuses set, otherwise this helper will throw and process it as a ServerFailure

onError can be provided to handle a specific exception on your repo/service, if you return null, it will be interpreted as not handled and the function will proceed to handle it itself

successStatuses let you define what status will be considered as a successful response so your response will be delegated to the onResponse callback By default this value is [200, 201, 202, 203, 204]

debugRequestBody let you specify if this method should log the body passed to the API, sometime you may want to keep it secret if you are submitting sensitive information Defaults to true

Implementation

@override
Future<Either<Failure, T>> wrapAndHandleHttpRequestResponse<T>(
  Future<Response> Function() futureResponse, {
  required DataOrFailureHandleResponse<T> onResponse,
  DataOrFailureHandleException<T>? onError,
  List<int> successStatuses = const [200, 201, 202, 203, 204],
  bool debugRequestBody = true,
}) async {
  failureCbk(Failure failure) {
    return Left<Failure, T>(failure);
  }

  rightCbk(T result) {
    return Right<Failure, T>(result);
  }

  try {
    try {
      final response = await futureResponse();

      logger.t("Request to ${response.request?.url} performed");
      if (debugRequestBody && response.request != null) {
        _logRequestBody(response.request!);
      }

      if (successStatuses.contains(response.statusCode)) {
        return onResponse(response, failureCbk, rightCbk);
      }

      throw ServerException.fromResponse(response);
    } catch (error, stackTrace) {
      // check if user have a specific handler for this exception
      final Either<Failure, T>? handle = onError?.call(error, failureCbk, rightCbk, stackTrace);
      if (handle != null) {
        return handle;
      }
      logger.t("Error not handled by user, so handling by default logic");
      // if it was not handled then rethrow so we handle it ourselves
      rethrow;
    }
  } on ServerException catch (error, stackTrace) {
    logger.e("ServerFailure", error: error, stackTrace: stackTrace);
    return left<Failure, T>(
      ServerFailure.fromServerException(error),
    );
  } on SocketException catch (error, stackTrace) {
    logger.e("InternetConnectionIssueFailure", error: error, stackTrace: stackTrace);
    return left<Failure, T>(
      InternetConnectionIssueFailure.fromSocketException(error),
    );
  } catch (error, stackTrace) {
    logger.e("UnknownFailure", error: error, stackTrace: stackTrace);
    return left<Failure, T>(UnknownFailure.fromException(error));
  }
}