https://kotlinlang.org logo
Title
g

Goku

04/13/2021, 12:25 PM
Hello guys, I’m pretty new to KTOR and Kotlin in general… I’ve created a simple multiplatform project, and I’m calling the following endpoint from the iOS side:
<https://api.github.com/projects/columns/42>
in order to receive 401, which is intended. Unfortunately, the program crashes with the following explanation:
Exception doesn't match @Throws-specified class list and thus isn't propagated from Kotlin to Objective-C/Swift as NSError.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: io.ktor.client.features.ClientRequestException: Client request(<https://api.github.com/projects/columns/42>) invalid: 401 Unauthorized. Text: "{"message":"Requires authentication","documentation_url":"<https://docs.github.com/rest/reference/projects#get-a-project-column>"}"
I get back the response and everything gets logged properly. Any idea on how to fix this? Thanks!
r

Rustam Siniukov

04/13/2021, 1:28 PM
you can disable default request validation by setting
expectSuccess = false
on client or per-request level
g

Goku

04/13/2021, 1:57 PM
Yeah, I figured that one out, thanks 🙂
I also need help with the following:
this.install(HttpSend) {
            intercept { httpClientCall, httpRequestBuilder ->
                val statusCode = httpClientCall.response.status.value

                if (statusCode !in 100..399) {
                    val delayBetweenRequests = retryStrategy.retryDelay(httpClientCall) ?: 0.0
                    delay(maxOf(delayBetweenRequests, 0.0).toLong())
                    execute(httpRequestBuilder)
                } else {
                    httpClientCall
                }
            }

            maxSendCount = retryStrategy.retryCount
        }
    }
For some reason I keep getting the following exception:
Uncaught Kotlin exception: io.ktor.client.features.SendCountExceedException: Max send count 3 exceeded
But I don’t understand how this is possible
Also, sorry for being so pushy 😄 I have this:
install(Auth) {
        basic {
            username = "myUsername"
            password = "myPassword"
            // sendWithoutRequest = true
        }
    }
/**
* Send credentials in without waiting for [HttpStatusCode.Unauthorized].
*/
var sendWithoutRequest: Boolean = false
The request that gets executed returns 401 (Unauthorized) but it doesn’t get re-executed with the
Authorization
header… I can only send it once I set
sendWithoutRequest = true
which I really don’t want to do for every request. Any help would be greatly appreciated! Thanks!
r

Rustam Siniukov

04/13/2021, 2:37 PM
for
SendCountExceedException
what exactly is wrong? It seems like you send more then 3 retries, and it’s your current limit
g

Goku

04/13/2021, 2:42 PM
This is what I see in
HttpSend.kt
class:
if (sentCount >= maxSendCount) {
    throw SendCountExceedException("Max send count $maxSendCount exceeded")
}
So once it reaches 3 it will throw an exception, so I don’t understand how I can fix this on my side? All I do is set the
maxSendCount = 3
in here:
this.install(HttpSend) { 
    intercept { httpClientCall, httpRequestBuilder ->
        ...
    }

    maxSendCount = 3
}
I’m probably doing something wrong here I just don’t see it
r

Rustam Siniukov

04/13/2021, 2:43 PM
what is your expected behavior?
g

Goku

04/13/2021, 2:44 PM
To retry it n times and then just stop retrying. Throwing an exception crashes it on iOS, that’s why this is a problem for me
Exception doesn't match @Throws-specified class list and thus isn't propagated from Kotlin to Objective-C/Swift as NSError.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: io.ktor.client.features.SendCountExceedException: Max send count 3 exceeded
I don’t mind the exception actually. Just need to figure out how to stop the app from crashing once it’s thrown. I’m really new to KMM so sorry if these are stupid questions.
r

Rustam Siniukov

04/13/2021, 2:46 PM
you can create a counter on your side and stop calling
execute
in your interceptor once it reaches desired value
something like
this.install(HttpSend) {
            var couter = 0
            intercept { httpClientCall, httpRequestBuilder ->
                val statusCode = httpClientCall.response.status.value

                if (counter < 3 && statusCode !in 100..399) {
                    ...
                    execute(httpRequestBuilder)
                    counter++
                } else {
                    httpClientCall
                }
            }
        }
g

Goku

04/13/2021, 2:49 PM
Yeah got you, that works. Just to clarify how this mechanism works. It will keep repeating the request until it gets a success response?
r

Rustam Siniukov

04/13/2021, 2:54 PM
or you reach desired retry count
g

Goku

04/13/2021, 2:56 PM
👍 thanks for your help
r

rsetkus

04/14/2021, 1:46 PM
Hi @Rustam Siniukov. Have very similar case so, will drop my question in this thread. I am using
HttpSend
to intercept response for authentication purposes. On 401/Unauthorized response intercepting and performing actions to refresh token and retry request. When
expectSuccess
is turned on (value true), 401 response is not intercepted. I guess it happens due to
ExpectSuccess
feature, which throws exception just before
HttpSend
feature and stops proceeding ktor pipeline. When I turn off
expectSuccess
(value false), response is intercepted in
HttpSend
and authentication works as expected. However, none of the
HttpResponseValidator
functions (validateResponse and handleResponseException) are called. Can you suggest or what is preferred way to map http errors to custom errors when
expectSuccess
is off?
r

Rustam Siniukov

04/14/2021, 1:59 PM
hi @rsetkus. What version of Ktor do you use? We had a bug that
expectSuccess=false
will disable all validators, and not only the default one. It was fixed in 1.5.2 https://youtrack.jetbrains.com/issue/KTOR-2007. Another point, please consider using
Auth
feature and implementing custom
AuthProvider
instead of intercepting
HttpSend
. Internally it will do the same, but it is more idiomatic way. Not a big deal, though
r

rsetkus

04/14/2021, 2:10 PM
Thank you for prompt response @Rustam Siniukov. This is it, I’m using version 1.5.0. Will try to switch to 1.5.2 to see if the issue disappears. Can see that
HttpSend
is marked as experimental so, definitely will consider option re-implement authentication using
AuthProvider
.
r

Rustam Siniukov

04/14/2021, 2:11 PM
If you are updating anyway, update to 1.5.3 😃
👍🏻 1
r

rsetkus

04/14/2021, 4:22 PM
Hi @Rustam Siniukov. Updated to 1.5.3. Like you said, it does fix/trigger custom validators but
HttpSend
doesn’t intercept response anymore.
r

Rustam Siniukov

04/14/2021, 6:31 PM
@rsetkus can you share example, please?
r

rsetkus

04/14/2021, 6:33 PM
@Rustam Siniukov working an a private project but can try to make a minimal reproducable example.
Hi @Rustam Siniukov. If that helps, then example I followed is this https://github.com/icerockdev/moko-network/issues/37#issuecomment-709420620. Can make complete example if necessary. Let me know.
r

Rustam Siniukov

04/15/2021, 11:31 AM
The best is if you create youtrack issue and put reproducer there