I have two Http4s
routes:
val routes1:HttpRoutes[Task] = ???
val routes2:HttpRoutes[RTask] = ???
Where RTask
is just a Task/RIO
with a custom environment:
type RTask[A] = RIO[Env,A]
Composing of two routes with the same type parameters can be accomplished by importing "zio-cats-interop" library and doing regular routes1<+>routes1
, but because the type parameter of HttpRoutes
is invariant, I can't do the same for different types:
routes1<+>routes2 /// error here
Is there any solution for this?
Let's dealias things:
type HttpRoutes[F[_]] = Http[OptionT[F, *], F]
type Http[F[_], G[_]] = Kleisli[F, Request[G], Response[G]]
so your HttpRoutes[RTask]
is in fact Kleisli[OptionT[RTask, *], Request[RTask], Response[RTask]]
.
Let's say you have applyR: RTask ~> Task
(which applies R) and requireR: Task ~> RTask
(which adds R that won't be used).
val applyR: RTask ~> Task = new (RTask ~> Task) {
def apply[A](rtask: RTask[A]): Task[A] = ... // apply Env here
}
val requireR: Task ~> RTask = new (Task ~> RTask) {
def apply[A](task: Task[A]): RTask[A] = ... // require Env here
}
You could adapt each of Kleisli's: input, output, effects using them, although it will be a chore:
val routesRTask: HttpRoutes[RTask]
val routesTask: HttpRoutes[Task] =
Kleisli { (reqTask: Request[Task]) =>
val reqRTask: Request[RTask] = req.mapK(requireR)
val responseRTask: OptionT[RTask, Response[RTask]] = routesRTask(reqTask)
responseRTask.mapK(applyR) // OptionT[Task, Response[RTask]]
.map(_.mapK(applyR)) // OptionT[Task, Response[Task]]
}
You could extract the logic above to some function and apply it to all routes which should be converted from RTask
to Task
.