FullStack-Swift / TodoList

Examples App Todo for Composable Architecture with UIKit and SwiftUI, and with RxSwift, ReactiveSwift and Combine
22 stars 8 forks source link

Handling Error #1

Open WHuangz88 opened 2 years ago

WHuangz88 commented 2 years ago

Hi Nguyen, it's such a great example But would you mind handling the error as well in the reducer when calling an API especially using Single instead Observeable

Thank you

NguyenPhongVN commented 2 years ago

Hi William Huang. Thanks for your comment, you can catch error by using catchToEffect, it is like that. Screenshot 2022-01-27 at 5 00 21 AM

NguyenPhongVN commented 2 years ago

l don't know which project l used Observeable in, can you give me more information. I'm currently editing the project, if you have problem, let me know. Thanks.

WHuangz88 commented 2 years ago
Screen Shot 2022-01-27 at 10 03 18

this it, cause lot of my project are using Single for the networking call, and I have tried using catchToEffect and it's not working do you have any idea how?

WHuangz88 commented 2 years ago
Screen Shot 2022-01-27 at 10 07 13

for my current solution is I have to map my Single to Observeable and then wrap it using materialize so i can expect an Observable<Event<Element>> and then i flatMapLatest to get the .next | .error | .completed result

do you have a better solution (?)

NguyenPhongVN commented 2 years ago
Screen Shot 2022-01-27 at 10 03 18

this it, cause lot of my project are using Single for the networking call, and I have tried using catchToEffect and it's not working do you have any idea how?

actually, I also use Single in Networking

extension DataRequest: ReactiveCompatible {

}

extension Reactive where Base: DataRequest {
   @discardableResult
   public func response(queue: DispatchQueue = .main) -> Single<AFDataResponse<Data?>> {
     Single.create { [weak base] single in
       let cancellableToken = base?.response(queue: queue) { response in
         single(.success(response)
         )
       }
       return Disposables.create {
         cancellableToken?.cancel()
       }
     }
   }
}

because Effect is a wrapper of Observable and Single too, so we must convert to Observable to switch Effect and Single. Screenshot 2022-01-27 at 12 55 01 PM Screenshot 2022-01-27 at 12 55 39 PM

before you using eraseToEffect(), convert it to an Observable.

extension Single {
  public func catchToEffect() -> Effect<Result<Element, Error>> {
    self.asObservable().catchToEffect()
  }
}
NguyenPhongVN commented 2 years ago

https://github.com/FullStack-Swift/TodoList/issues/1#issuecomment-1022805159 your way is very cool,l have some suggestion:


public struct AnyError<Failure: Error>: Error {

public var error: Failure

public init(error: Failure) { self.error = error } }

public extension Error { func asAnyError() -> AnyError { AnyError(error: self) } }

extension AnyError: Equatable where Failure: Equatable {}

struct HttpError: Error, Equatable { var errorString: String }

enum MainAction: Equtable { case responseTodo(Result<Data, AnyError>) }



![Screenshot 2022-01-27 at 1 05 55 PM](https://user-images.githubusercontent.com/50719947/151301496-42c77f09-3dae-4820-a96a-9df0da7a3a0e.png)
NguyenPhongVN commented 2 years ago

I don't think it is better, do you have any idea?

WHuangz88 commented 2 years ago

Now I get it, and both way are actually good, depends on the expected output maybe 😀.

I think mine is more like that I want to show an error alert immediately rather than processing the response data, and so I could just focus on the error action of what the view should behave when an error is produced

mean while yours like you want to show both error and data to user (?)

NguyenPhongVN commented 2 years ago

My backend maybe return the Error in Result.success, you can check in here. https://todolistappproj.herokuapp.com/todos/ https://todolistappproj.herokuapp.com/todos/1 so l want check the error in my case .success to handle error. 😃