4
votes

I have a project where I'm using Moya with RxSwift extensions. The simple use cases work fine, I'm able to do requests and get responses in the form of Observables.

public func test() -> Observable<Response> {
    return provider
    .request(.test)
    .retry(5)
}

I can then subscribe to the observable and print the response with no problem.

But now I need to handle authentication logic. The way it works is that I run the above request with a token added as an HTTP Header Field. Moya allows me to that transparently by using endpointByAddingHTTPHeaderFields in the endpointClosure. No problem so far.

The problem arises when the request fails with HTTP status 401, that means I need to re-authenticate by calling another endpoint

provider.request(.auth(user, pass)).retry(5)

This returns another Observable that I can easily map to JSON to get the new token.

I then just have to call test() again!

So my question is... How can I add this authentication logic inside the test() function above, so that the Observable returned by test() is already guaranteed to have run the re-authentication logic in case of failure and be the result of a second re-authenticated request.

I'm very new to RXSwift and RX in general, so I'm a bit clueless about the operators I would use to do this.

Thanks!

1
Did you ever solve this?tskulbru
Does the 401 come through as an error, or is it a valid response object?Daniel T.
If the former, this answer might help you out: stackoverflow.com/questions/35841054/…Daniel T.

1 Answers

-1
votes
public func test(with authToken: String) -> Observable<Response> {
    return provider
      .request(.test)
      .endpointByAddingHTTPHeaderFields(["Authorization": authToken])
      .catchError { error in
        if needsReauth(error) {
          return provider.request(.auth(user, pass)).map { parseToken($0) }
            .flatMap { token in
              return test(with: token)
            }
        } else {
          return .error(error)
        }
      }
}

catchError enables to continue observable's execution using another observable. The observable we define here does the following:

  1. First, it will request the .auth endpoint.
  2. It then reads from the response to get the new auth token
  3. Finally, we recursively call test(with authToken: String) to retry querying the test enpoint.