I'm making a helper library for Ktor, and I'm torn...
# arrow
c
I'm making a helper library for Ktor, and I'm torn as to whether force Arrow as a dependency of it. I believe the best experience for the library would be when used alongside Arrow, and if I make Arrow optional, that will add a (very small) amount of boilerplate to Arrow users. But at the same time, this is an HTTP library and Arrow is quite a different library, and I may face users who want to use my library but are somehow against Arrow. If you have faced similar design decisions in the past, how have you made your decision? Have you had experience with projects that added Arrow to their dependencies not because they wanted to use Arrow, but because it was a transitive dependency of some other library they wanted to use, and if so, how did people react?
👀 2
k
You could try follow some adapter pattern and publish another module which wraps your functionality behind the patterns and API’s that Arrow provides. Something similar to the popular Retrofit library.
c
Well, the point of
Raise
is to be part of the signature.
r
I don't have an easy answer for you, but when adding a library to a project, I always think about what the implications for my dependency tree are. Transitive dependencies are one more thing I have to manage and think about.
r
What would one of these arrow enabled routes look like for the point of view of what a user had to provide ?
c
The short version is, using the
Raise
DSL to short-circuit when some data is invalid and you want to return an error to the user.
(and same thing on the client-side)
r
I'm currently using Arrow with Ktor and Spring boot in a client where we did not introduced Arrow, they did. The reason they are using Arrow is the same one you mention here, having a form of typed errors. For them to introduce Arrow themselves have been challenging mainly because they navigated our Either -> Raise journey and for the most part they are stuck with Either in a bunch of places. They could have benefited from an opinionated way to have routes and client to those routes already integrating typed errors. I'm not sure if Arrow belong in your core lib but would definitely be useful to have an arrow module to interface with Ktor's route boilerplate. For example: https://github.com/nomisRev/ktor-arrow-example/blob/main/src/main/kotlin/io/github/nomisrev/routes/profile.kt#L59-L68
Copy code
post<ProfilesResource.Follow> { follow ->
    jwtAuth(jwtService) { (_, userId) ->
      either {
          userPersistence.followProfile(follow.username, userId)
          val userFollowed = userPersistence.select(follow.username).bind()
          ProfileWrapper(Profile(userFollowed.username, userFollowed.bio, userFollowed.image, true))
        }
        .respond(HttpStatusCode.OK)
    }
  }
Could probably look like:
Copy code
post<ProfilesResource.Follow> { follow ->
    jwtAuth(jwtService) { (_, userId) ->
       userPersistence.followProfile(follow.username, userId)
       val userFollowed = userPersistence.select(follow.username).bind()
       Ok(ProfileWrapper(Profile(userFollowed.username, userFollowed.bio, userFollowed.image, true)))
    }
  }
or similar, including validation functions and other's. A redefinition of
post
and similar operators from Ktor to include the
Raise
context would eliminate the need for
Either
wrapping/unwrapping and specialized extensions functions like https://github.com/nomisRev/ktor-arrow-example/blob/147b8642fbb2f8c351436ff213610b9472153334/src/main/kotlin/io/github/nomisrev/routes/error.kt#[…]4
👀 1
s
My goal of making Arrow 2.0 so small, was that you could use
Raise
without that concern but I imagine that's not how people will react when they see "Arrow" as a dependency.. Arrow Core will be extremely small, much smaller than Kotlin Std or KotlinX Coroutines and everyone has that on the classpath. It depends the most on the goal of your library tbh @CLOVIS, and it's a tricky decision. I've split the core in a bit more pieces, for example "autoclose DSL" since I am going to use that in a bunch of libraries and now it's a 1 file library that probably will never change... And I am doing the same for
SuspendApp
I am going to make it depend on
Resource
(file) and
AutoClose
(file), and that'll turn into a "terminal signal coroutinescope library". Depending on
Raise
, or
Either
is more controversial to something like that though.
👀 1