1

I have a simple server request that I want to filter and generate a new Observable validating the request with the JSON data.

I have to do this because even when my request is invalid, my server response returns status code 200. But I can filter this result in my Json response:

Server response:

<NSHTTPURLResponse: 0x7fb2d2617850> { URL: http://service-.herokuapp.com/--} { status code: 200, headers ...

Json:

{"system": {"code": "401","message": "Access Not Authorized"}}

My rx request is:

let manager = Manager.sharedInstance
return manager.rx_request(method, "\(ApiRoutes.baseURL)\(path)", parameters: parameters)
// then validate server response
.flatMap{
     $0.validate(statusCode: 200..<300)
     .rx_responseData()
}
// then I create a new Observable validating the received json
.flatMapLatest { response, data in
     return Observable.create{ observer in
          let json = JSON(data: data)

          let statusCode = Int(json["system"]["code"].numberValue) ?? 400

          if 200..<300 ~= statusCode {
                observer.onNext((response,data))
          }else{
                observer.onError(NSError(domain: "test", code: 1, userInfo: nil))
          }
          observer.onCompleted()
          return NopDisposable.instance
     }
}
.observeOn(MainScheduler.instance)

My question is: When my json pass (status code between 200 and 300) I send an Event Next and after an Event Complete, this completes this signal and first signal Completes as well. But when I send an Event Error when validating my JSON the first signal never completes or fail. How can I do this?

Thank you

Antonio Junior
  • 469
  • 6
  • 13

1 Answers1

3

An observable can only send either one completed event or one error event.

You need to update your flatMapLatest code to not send onCompleted() after an error.

if 200..<300 ~= statusCode {
    observer.onNext((response,data))
    observer.onCompleted()          
}else{
    observer.onError(NSError(domain: "test", code: 1, userInfo: nil))
}

Another remark, that may simplify the chain: you could, instead of creating a new Observable in a flatMapLatest method, replace it with a map operation that throws

return manager.rx_request(method, "\(ApiRoutes.baseURL)\(path)", parameters: parameters)
// then validate server response
.flatMap{
     $0.validate(statusCode: 200..<300)
     .rx_responseData()
}
.map { (response, data) in
    let json = JSON(data: data)
    let statusCode = Int(json["system"]["code"].numberValue) ?? 400

    if 200..<300 ~= statusCode {
        return (response,data)
    } else {
        throw NSError(domain: "test", code: 1, userInfo: nil)
    }
}

This way, you don't need to handle the forwarding of .Next and .Completed events yourself, and your block only focuses on one thing, generating errors.

tomahh
  • 13,441
  • 3
  • 49
  • 70