David Tamrazov
David Tamrazov

Reputation: 597

How to create a recursive callback for token exchange, Swift

My app uses access tokens with short expiry timers to authenticate users when making server calls. When a call is made with an expired token, the server responds with a 402 status, and the user has to then send a refresh token that will prompt the server to send back a fresh access token. I would then need to make the EXACT same server call with the exact same arguments that I had in the first place, but now with my new access token. How can I automate this process so that the token exchange happens and we get the resource we initially wanted, without any user input (i.e. it all happens in the background, the user isn't even aware of it)? I cant think of a way that doesn't involve making horrendous nested calls like so:

someAPICall(foo, arg2: bar) { result, error in 
    if let result = result {
        if result.status == 402 {
           performTokenExchange(refreshToken) { newAccessToken, error in 
               if newToken {
                  someAPICall(foo, bar) { result, error in 
                      //... 
                  }
               } 
           }
        }
        else {
           // ... continue with program
        }
    }    
} 

My first thought would be to bring recursion into the picture, and recursively call "someAPICall" within the "performTokenExchange" callback, but then I don't know how to handle "someCall" without explicitly managing it within the "performTokenExchange" callback, landing me back at my "horrendous nested call" issue.

Upvotes: 3

Views: 747

Answers (1)

Keiwan
Keiwan

Reputation: 8251

While I haven't tried this myself, I think you should be able to use recursion when writing your closure and then pass that as an argument to the function when calling it.

var completion: ((Result?, Error?) -> Void)!    // change this to whatever types your result and error are

completion = { result, error in

    if let result = result {
        if result.status == 402 {

            performTokenExchange(refreshToken) { newToken, error in
                if newToken {
                    someAPICall(foo, bar, completion)
                }
            }
        } else {
            // ... continue with program
        }
    }
}

So you first declare your completion closure as an implicitly unwrapped optional with its specific type. Then you can assign the actual block of code to completion where you will be able to refer to completion again, since it was declared beforehand.

Like this, you should be able to make the API call like:

someAPICall(foo, bar, completion)

(just as it is also used inside the closure itself)

Let me know if this works! As said this is just an idea and not tested :)

Upvotes: 1

Related Questions