How do you keep your ktor client setup in common w...
# ktor
u
How do you keep your ktor client setup in common while having different engines per platform, while each platform has its config in the
engine { ... }
block? If it were somehow on the Engine object, then I'd get it, I'd just expect actual the Engine factory ...or do I have to expect actual both factory for Engine AND the engine block?
c
If we're only talking about the client, you don't need to expect-actual anything, the
HttpClient
constructor is in common
u
but how do I pass it the platform engine, if not for expect actual?
c
Do you need to?
Copy code
// commonMain/kotlin/Client

fun createClient() = HttpClient {
    install(Logging) { … }
    install(ContentNegotiation) { … } 
}
This works
u
hm but what engine does that choose?
u
right, but how do I then do platform config
say I want okhttp engine, but since reset of my android app already uses okhttp, so I want to share the engine
Copy code
engine {
   preconfigured = ...
}
I think my issie is with the api, if it were a simple builder pattern, then I'd just expect actual a
Copy code
actual createEngine(): HttpEngine
c
Ah, in that case you will need to expect-actual, yes. What you can do is to create an extension function on
HttpClientConfig<*>
which has your common configuration, and call it in your various actuals that add platform-specific config: https://gitlab.com/opensavvy/formulaide/-/blob/main/remote-client/src/commonMain/kotlin/Client.kt#L17
(
HttpClientConfig<*>
is the receiver of the
HttpClient {}
factory)
u
I see, so the other way around, extracting the common setup and calling it in platform specific code
thanks!
btw any chance you know how to create a hierarchy of ktor client instances?
I could share what you just proposed, and just apply it to multiple instances but that would mean multiple instances of the interceptors etc. is there a way to share them?
(say you have authenticated and unauthenticated apis - with okhttp I'd have 2 clients, first has some common setup, seconds inherits the common setup and adds auth handling)
c
In the example I showed you what's in the common code is just a factory, if you want to create multiple client instances you can call the factory multiple times
u
I know but those arent shallow copies of each other? the way
okhttp.newBuilder()
does
it will share the instances of interceptors, threadpools etc
c
I don't know if that's possible, maybe send a new message in the channel so other people see it (since that's essentially a new question)
u
I did, no response unfortunately
the idea is basically to have multiple instances, but share stuff so the latter instance is cheap
c
Not sure what plugins you're using, but I doubt it makes any difference for normal plugins
u
well, probably true, my interceptors in okhttp are trivial, but main thing is okhttp threadpools and all the internal resources, same things which make you want to cache the ktor httpclient instance, not create new one per call
c
Didn't you say you're using
preconfigured=
? In that case, you just have to pass the same object for both calls and they share the OkHttp instance
u
well yes, hmm which means the engine is the heavy part, and I could just share that?
c
I don't know OkHttp, so maybe there's a limitation on their side, but my understanding of Ktor is that you can, yes
u
I mean yes it will work, but whats confusing, is that there is already a concept of the shallow copy
you can
install(httpClient)
which in my mean read as apply all settings from the client to this which would then mean
Copy code
val baseClient = HttpClient {
   install(DefaultRequest)
   install(ContentNegotiation)
}

val authedClient = HttpClient {
   install(baseClient)
   install(Auth)
}
but its the other way around 🙄
which would then scale beautifully, you just ask for the parents instance in the DI and provide a child one to the DI other way around youre hardcoding all the children in the parent...nope