Hello, I have integrated Arrow with Ktor using `De...
# arrow
r
Hello, I have integrated Arrow with Ktor using
Deferred
class from
kotlinx.coroutines
, sample code is below. As you can see I have
DemoService
and
DemoRouting
which have no suspend method and are parametrized with type
F
. I define
F
as
IO
when the server is created (so on the end of the world ;)). I could use different monad (e.g.
Try
) after implementing the
Deferrable
interface. Please let me know what you think about this approach. @Bob Glamm, this is a little bit different than using
Async
directly as we spoken recently, there is a separate typeclass to transform value into deffered value.
s
I am not sure what the point is moving from
IO
->
Deferred
->
suspend
. Can you not just use
IO
->
suspend
?
b
That might be 0.9.0 code without
IO.suspended
s
Yes, but
Deferred
looks like the wrong data type here. No reason to introduce eagerness here when you can get away with keeping it pure by using
suspend
instead.
I attached a small snippet but I am not 100% sure about the Ktor API. I can help implement
Suspendable
if needed for
IO
. When you have
kotlinx
on the classpath you can also implement a cancellable version using
suspendCoroutineCancelable
.
r
Suspendable
is not present in 0.9.0 I can refactor it to
Suspendable
when 0.10.0 will be released 😄
b
huh. Is
Suspendable
in 0.10.0-SNAPSHOT?
I was having a lot of trouble with `Async`/`Effect` not having
suspended()
r
It's not, but @simon.vergauwen presented snippet with implementation, I'm trying to run it, but I need to make a break now
s
No,
Suspendable
is not there. It’s a temporary typeclass in that snippet
suspended()
will come to the Arrow Fx typeclass hierarchy in next releases. Most likely in
Effect
.
b
aha ok
s
If you guys are interested in enhancing the existing Ktor DSL with additional extension functions for Arrow I’d be glad to help out.
b
You already are! If we get one example working then the pattern is the same for the rest of the DSL
s
Awesome 👍
b
just try to bear with me as I ask more stupid questions 🙂
assuming I can get a break from work to work on this over the next day or two. I was Ragnaring all weekend (https://www.runragnar.com/event-detail/relay/minnesota#overview ) otherwise I would have worked on it more
s
Looks nice! A break to relax and empty the mind is always good.
r
Thanks @simon.vergauwen for help! I've ended with
Suspendable
(see code snippet below). In 0.10.0 I should be able to smoothly switch to
Suspendable
from Arrow. Please don't ask why I used this
Deferred
instead of suspend function directly, I have no idea 😉. Solution with with
Suspendable
is simpler and it is more easy to refactor for 0.10.0 in future.
s
Hi @Rafal Piotrowski, I am glad I could help! That looks super awesome!
r
If you don't mind I would like to describe it on Medium or something like that. I was googling how to integrate Arrow with Ktor a lot and I found nothing. I found some info and help finally here 🙂 I would like to describe how to make it in 0.9.0 and add a note that in 0.10.0 it will be even simpler 🙂
s
I don’t mind at all! I love seeing Arrow based content, and I think I speak for everyone in the Arrow community when I say that 😄 Swing by here for a proof read and don’t forget to PR a link to the Arrow blog https://arrow-kt.io/blog/ 😉
👍 1
b
I finally got a chance to look that over and I'm not sure where the integration with
call
should go. In my last attempt I tried to compose
PipelineContext
with
Async<F>
so that the program in
Async<F>
could decide what to do with the response. In the example above, the return type of
work.suspended()
would need to be robust enough for the code in the
get(...) { ... }
block to handle the complete response via methods on
call
.
I think I need to actually write a few non-trivial handlers to decide what encapsulation makes sense
s
I’d be happy to look over some code, that’ll tell me exactly what I need to know to understand the problem. Any repo or gist you could share?
b
Not yet, unfortunately. (Work has been exceptionally busy as of late.) I will try to create a few examples in the next week or so. In the meantime, just to give you an idea: ktor's API is such that methods of the form
(arg...) -> Unit
within the handler are common to form an HTTP response. For instance, the following set various HTTP response headers:
Copy code
response.etag("33a64df551425fcc55e4d42a148795d9f25f89d4")
response.lastModified(ZonedDateTime.now())
response.contentLength(1024L)
response.cacheControl(CacheControl.NoCache(CacheControl.Visibility.Private))
response.expires(LocalDateTime.now())
response.contentRange(1024L until 2048L, 4096L)
Methods with similar type signatures exist for setting the response status and emitting the response body. In terms of how this relates to `Kind<F, Response>`:
F
is usually at least as powerful as
MonadThrow
and the arguments supplied to the response methods are typically dependent on failure or success, so
.attempt()/.fold()
or
.catch()/.handleErrorWith()
seems reasonable, but in both of those cases the object in the handler (
call
) needs to be available within the effect. The other alternative I can think of is that
Response
is made robust enough so there is a direct mapping between
Response
and all of the methods on
response
, but it seems difficult and error-prone to re-encapsulate the entire
response
object.