arrow-kt / arrow

Λrrow - Functional companion to Kotlin's Standard Library
http://arrow-kt.io
Other
6.09k stars 440 forks source link

Retrofit+Arrow to Ktor Client+Arrow migration #3354

Open postfixNotation opened 6 months ago

postfixNotation commented 6 months ago

As of today I'm using Retroft in combination with Moshi for Serialization and Arrow's Either API for return type specifications, for instance suspended network calls return something like Either<CallError, Dto> where CallError is an Arrow API.

I'm slowly migrating my app to be multiplatform capable, so I'm replacing APIs like java.time. with kotlinx.datetime. and so on. My problem is, there's a Retrofit integration with Arrow but not an equivalent for Ktor as far as I know.

So my question is: what would be the best pattern or strategy to replace Retrofit with Ktor client so that my client code doesn't break? This is kind of tricky since CallError is located in arrow.retrofit.adapter.either.networkhandling, so it's part of Retrofit's integration API... For clarification: I'm also migrating from Moshi to kotlinx.serialization, maybe this helps somehow.

nomisRev commented 6 months ago

Hey @postfixNotation,

I think there are a couple of things we can do, but not sure which is the best one 🤔 It also depends a bit on your use-case.

  1. There is also Ktorfit, but the adapter we have doesn't work with that one but it should be very easy to port.

  2. We write a new module for Ktor, which I think multiple people have shown interest in. However, there are two options here

    • Re-use CallError from Retrofit library, this would be least breaking for you
    • Use different sealed class for Ktor, since it support different kind of errors. I think for Ktor Either<HttpStatusCode, A> might be better. Or data class CallError(val code: HttpStatusCode, val call: ApplicationCall), and Either<CallError, A>.
postfixNotation commented 6 months ago

Hi @nomisRev,

thanks for your quick and helpful reply!

Ktorfit looks pretty neat and it's good to know about this option. However I'm planning to delve into Ktor extensively since I'd also like to write my own backend. Also I want my project to have as few dependencies as possible and also to mostly rely on robust long-term solutions. Depending on intermediary layers/services is probably not sustainable for my requirements.

A module, as proposed in your last message, would be amazing and also very beneficial for the whole community. "Retrofit's" CallError might be exposed as a typealias in an appropriately scoped package of such a module which would be least breaking for me, as of my understanding. But a correctly modeled approach, as described in your last point, might probably be the most beneficial solution.

Is there an estimation of how long this might take? Thanks!

nomisRev commented 5 months ago

Hey @postfixNotation,

Is there an estimation of how long this might take?

There is only a couple of maintainers, and sadly this is on none of our priority list. We already have more work than we can handle in our spare free time.

However, if you'd like to work on this I'd be more than happy to guide, and support you! ☺️

postfixNotation commented 5 months ago

Hi @nomisRev,

As soon as I migrate from Retrofit to Ktor to make my app multiplatform compatible I will consider working on this feature. Right now I have zero knowledge of and experience with Ktor's API surface and paradigm which is why it's hard to make any commitments.

But this could be my first open source contribution which is pretty exciting and a good learning experience, so we'll see :-)

I'm also looking for a good multiplatform DI solution but the existing one's are too risky since many of them don't provide compile time safety. I came across Kotlin context receivers and their potential ability to act as 3rd party DI framework replacement.

I know it's not related to this issue but is there still any work in progress from Arrow's site with respect to this functionality? The respective repository seems not to be actively maintained anymore.

Have a great weekend!

abendt commented 2 months ago

Hi @nomisRev and @postfixNotation

would be interested to work on that and provide a PR

I have experimented a bit and already have a basic adapter for KtorFit but would also like to check out option #2

Please let me know if that's OK for both of you

postfixNotation commented 2 months ago

Hi @nomisRev and @postfixNotation

would be interested to work on that and provide a PR

I have experimented a bit and already have a basic adapter for KtorFit but would also like to check out option #2

Please let me know if that's OK for both of you

It would be amazing if someone worked on this issue since I have different priorities at the moment :-)

abendt commented 2 months ago

Here is my result so far: https://github.com/abendt/arrow-ktor/blob/main/src/main/kotlin/demo/ExampleApi.kt

There you can see how you can use Either<Exception, A> in your Ktorfit client. Should also be possible to support some custom CallError on the left side.

Let me know if that looks useful to you and what other requirements & ideas you might have

postfixNotation commented 2 months ago

Here is my result so far: https://github.com/abendt/arrow-ktor/blob/main/src/main/kotlin/demo/ExampleApi.kt

There you can see how you can use Either<Exception, A> in your Ktorfit client. Should also be possible to support some custom CallError on the left side.

Let me know if that looks useful to you and what other requirements & ideas you might have

Hi @abendt! This looks pretty interesting and very easy to use.

I'm still stuck with Retrofit but I assume I would migrate to Ktor Client without using Ktorfit. Although it looks pretty straight forward to use.

I think the most pragmatic and helpful approach would be to work on solution 2.2) of @nomisRev post above.