kean / Get

Web API client built using async/await
MIT License
943 stars 75 forks source link

APIClientDelegate functions not called? #17

Closed bonkowski closed 2 years ago

bonkowski commented 2 years ago

Hi!

I'm trying to get Get to work in my current project, and have created a small struct implementing a simple call to our backend. I need to set a token in the header for each call, so I have implemented a APIClientDelegate like this: (more or less a copy of the sample in the readme)

 final class AuthorizingDelegate: APIClientDelegate {
    func client(_ client: APIClient, willSendRequest request: inout URLRequest) async throws {
        print("-- client:willSendRequest")
        request.allHTTPHeaderFields = ["Authorization": "Bearer \(await getToken())"]
    }

    func shouldClientRetry(_ client: APIClient, withError error: Error) async throws -> Bool {
        print("-- client:withError")
        if case .unacceptableStatusCode(let statusCode) = (error as? APIError), statusCode == 401 {
            return await !getToken().isEmpty
        }
        return false
    }

    func client(_ client: APIClient, didReceiveInvalidResponse response: HTTPURLResponse, data: Data) -> Error {
        print("-- client:didReceiveInvalidResponse:data")
        return APIError.unacceptableStatusCode(response.statusCode)
    }

    func getToken() async -> String {
        await withUnsafeContinuation { continuation in
            Auth.auth().currentUser?.getIDToken(completion: { token, error in
                continuation.resume(returning: token ?? "")
            })
        }
    }
}

The request I'm testing looks like this:

struct ReqTest {
    let delegate = AuthorizingDelegate()
    func testMe() async -> String {
        let client = APIClient(host: "xxxxxx.xxxx") {
            $0.sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
            $0.delegate = delegate
        }
        do {
            let req = Request<MyResponse>.get("/api/user")
            let resp = try await client.send(req).value
            return resp.nickname
        } catch {
            print(error)
            return error.localizedDescription
        }
    }
}

When calling testMe(), this us what is logged:

-- client:didReceiveInvalidResponse:data
unacceptableStatusCode(401)
Response status code was unacceptable: 401.

I would expect to see a call to the other delegate functions to get the neccessary token, but this is not the case. Any clue?

bonkowski commented 2 years ago

After a good night sleep, I looked at the problem again. I based my code on the code found in the readme file, where the implementation of the delegate methods throws, which is not how they are defined. This explains why my metods didn't get called.

kean commented 2 years ago

implementation of the delegate methods throws, which is not how they are defined

This is a recent change. I will create a new release soon.