alhussien aldali
alhussien aldali

Reputation: 139

Handling Errors with Dio/bloc Flutter

I need a good way to handle errors while I'm Using Dio requests. Can I do it in one class and pass the dio request throw it ? and it should return a response with the error .

Upvotes: 3

Views: 1318

Answers (1)

Jay Dangar
Jay Dangar

Reputation: 3469

I am posting my generalized network bloc here, which can be reused any number of time, any where. also, It uses dio using API repository , exceptional and error handling.

class NetworkBloc extends Bloc<NetworkEvent, NetworkState> {
  NetworkBloc() : super(NetworkRequestInitial());

  @override
  Stream<NetworkState> mapEventToState(
    NetworkEvent event,
  ) async* {
    yield NetworkRequestInitiated();
    if (event is NetworkCallEvent) {
      RequestType requestType = event.requestType;
      if (requestType == RequestType.GET) {
        yield* fetchData(event);
      } else if (requestType == RequestType.POST) {
        yield* uploadDataAndStoreResult(event);
      }
    }
  }

  Stream<NetworkState> fetchData(NetworkCallEvent event) async* {
    Response response;
    try {
      yield NetworkRequestLoading();
      response =
          await event.apiRepository.sendGetRequest(event.url, event.request);
      if (response.statusCode == 200) {
        yield NetworkRequestLoaded(response: response);
      } else {
        Map jsonResponse = jsonDecode(response.data);
        yield NetworkRequestFailure(message: jsonResponse['message']);
      }
    } catch (e) {
      yield NetworkRequestFailure(
          message: NetworkUtils.getErrorMessageAccordingToError(e));
    }
  }

  Stream<NetworkState> uploadDataAndStoreResult(NetworkCallEvent event) async* {
    Response response;
    try {
      yield NetworkRequestLoading();
      if (event.request != null) {
        if (event.isHeadersNeeded) {
          response = await event.apiRepository.sendPostRequestWithHeader(
            event.url,
            request: event.request,
          );
        } else {
          response = await event.apiRepository.sendPostRequest(
            event.url,
            event.request,
          );
        }
      } else {
        response = await event.apiRepository
            .sendPostRequestWithoutBodyParameters(event.url);
      }
      if (response.statusCode == 200) {
        saveDataAccordingToCacheMechanism(event, response);
        yield NetworkRequestLoaded(response: response);
      } else {
        Map jsonResponse = jsonDecode(response.data);
        yield NetworkRequestFailure(message: jsonResponse['message']);
      }
    } catch (e) {
      yield NetworkRequestFailure(
          message: NetworkUtils.getErrorMessageAccordingToError(e));
    }
  }

  void saveDataAccordingToCacheMechanism(
      NetworkCallEvent event, Response response) async {
    if (event.cacheMechanism == CacheMechanism.SharePreferences) {
      Hive.box(ConstUtils.dbName)
          .put(event.keyForSharedPreferences, response.data.toString());
    } else if (event.cacheMechanism == CacheMechanism.Database) {}
  }
}

I am also adding states and events to make it more easy to understand.

class NetworkCallEvent extends NetworkEvent {
  final String request;
  final dynamic url;
  final RequestType requestType;
  final CacheMechanism cacheMechanism;
  final String keyForSharedPreferences;
  final APIRepository apiRepository;
  final bool isHeadersNeeded;

  NetworkCallEvent(
      {@required this.url,
      this.request,
      this.isHeadersNeeded = false,
      @required this.requestType,
      @required this.apiRepository,
      @required this.cacheMechanism,
      this.keyForSharedPreferences});

  @override
  List<Object> get props => [
        this.url,
        this.request,
        this.requestType,
        this.cacheMechanism,
        this.keyForSharedPreferences,
        this.apiRepository
      ];
}

Network_states:

class NetworkRequestInitial extends NetworkState {}

class NetworkRequestInitiated extends NetworkState {}

class NetworkRequestLoading extends NetworkState {}

class NetworkRequestLoaded extends NetworkState {
  final dynamic response;

  NetworkRequestLoaded({this.response});

  @override
  List<Object> get props => [this.response];
}

class NetworkRequestFailure extends NetworkState {
  final String message;

  NetworkRequestFailure({this.message});

  @override
  List<Object> get props => [this.message];
}

You can easily send request in JSON and get Response in dynamic, which you can convert to appropriate object using json.decode().

Upvotes: 1

Related Questions