Search code examples
flutterstreamrxdart

rxDart not calling onError


I am trying to make a simple request to backend using rxDart. But the problem I face is that when I get a http error such as 404, onError is not called, however, it is possible to extract it in onData.

I have a little experience with RxJava + retrofit and there it works as expected, when there is a response with error http status code onError is called and can be handled appropriately.

1. What am I doing wrong, or is it intended behavior?.

  Object sendProfileData() {
    Stream<Response> stream = onboardingRepository.createUser(User(name: 'name', surname: 'surname', lat: 1.0, lng: 2.0));
    stream.listen((response) {
      print(response.statusCode);
      setAttributes();
    }, onError: (e) {
      print(e);
    });
  }

OnboardingRepository.dart:

class OnboardingRepository {
  Observable<Response> createUser(User user) {
    return Observable.fromFuture(TMApi.createUser(user));
  }
}

TMApi.dart:

class TMApi {
  static Future<http.Response> createUser(User user) async {
    String url = '$baseUrl/create_user';
    return await http.post(url, body: json.encode(user.toJson()));
  }
}
  1. What would be the best way to handle the event in the View? There should be an error displayed if error occurs, otherwise it should open a new screen. sendProfileData() method will return an Object, based on that I am going to perform actions in the view, but that doesn't sound like a very elegant solution...

  2. Any suggestions on architecture are welcome :)


Solution

  • the http library in dart works a bit different than Retrofit.

    The Future returned by http.post only throws an exception when there is an io error (socket error, no internet).

    Server responses like 404 are reflected in the http.Response.

    I created a simple convenience method that might help you:

    void throwIfNoSuccess(http.Response response) {
      if(response.statusCode < 200 || response.statusCode > 299) {
        print('http error!');
        print(response.body);
        throw new HttpException(response);
      }
    }
    
    class HttpException implements Exception {
      HttpException(this.response);
    
      http.Response response;
    }
    

    How to use:

    import 'dart:convert';
    import 'package:http/http.dart' as http;
    
    Future<UserProfile> getUserProfile(String userId) async {
      final url = 'https://example.com/api/users/$userId';
    
      final response = await http.get(url);
    
      throwIfNoSuccess(response);
    
      final jsonBody = json.decode(response.body);
    
      return UserProfile.fromJson(jsonBody);
    }