0

I'm new to RxJava and am having a hard time with handling error cases. The application is in Kotlin but it probably won't make much of a difference. The scenario is basically user authentication and then performing an action but if the user is not authorized/has a bad auth token I generate an exception and want to cease processing. Right now I have my function that checks tokens and it looks like this.

fun checkAuthority(authToken: AuthToken, requiredAuthority: Authority): Completable =
    authorityRepository.getAuthorities(authToken)
        .filter { it == requiredAuthority }
        .switchIfEmpty { subscriber -> subscriber.onError(UnauthorizedException("must have '$requiredAuthority' authority")) }
        .ignoreElements()

Then I have a function that looks a bit like this that checks permissions then is supposed to do an operation if they are authorized.

fun create(model: EntityCreate, authToken: AuthToken): Single<Entity> =
    checkAuthority(authToken, CAN_WRITE_ENTITY)
        .andThen(entityRepository.insert(model, OffsetDateTime.now(clock)))

What I want is that if the UnauthorizedException is generated to not execute the andThen.

Perhaps there is a gap in my understanding of the documentation but I've for instance tried putting doOnError to throw the Throwable before the andThen. I've tried onErrorComplete in the same place. No matter what I do the andThen eventually executes.

What would the pattern look like to abandon the Completable chain should the subscriber.onError line executes?

Rig
  • 1,276
  • 3
  • 22
  • 43
  • That `switchIfEmpty` parameter is wrong, you should not create a reactive source that way. Use `switchIfEmpty(Observable.error(UnauthorizedException("...")))` instead at least. If you write `entityRepository.insert(model, OffsetDateTime.now(clock))` on its own, does it execute immediately or is it waiting for a subscription? If the former, wrap the entire call into `X.defer { entityRepository.insert(model, OffsetDateTime.now(clock)) }` of the appropriate reactive type X. – akarnokd Jul 18 '18 at 13:32
  • Wrapping the insert with Single.defer seemed to work as far as my tests go. Changing the switchIfEmpty as you described complained that it should be a Publisher and not an Observable. Could you perhaps write an answer and explain why defer worked here a little? I'd obviously accept it. Reading the javadoc on the defer function still leaves me a little confused as to why it accomplished my goal. "Calls a Callable for each individual SingleObserver to return the actual Single source to be subscribed to." is what the javadoc for Single.defer. – Rig Jul 19 '18 at 03:28
  • The types are not apparent in your code. Use Flowable.error then. Where does that entityRepository come from, what library? – akarnokd Jul 19 '18 at 06:52
  • The entityRepository in the case of an insert returns a Single. It's just an interface backed by a class storing data in a hashmap. This is a bit of a dummy app but I was going to back it with a proper data layer soon. The authorities are returned as a Flowable from a similar setup. – Rig Jul 19 '18 at 14:11

0 Answers0