如何用zio效果和不同类型的环境组合两个Http4s路由

问题描述

我有两条 use std::fs; use std::str::Chars; struct FileContents { filename: String,contents: String,} impl FileContents { fn new(filename: String) -> Self { let contents = fs::read_to_string(&filename).unwrap(); FileContents { filename,contents } } fn token_iter(&self) -> TokenIter<'_> { TokenIter { chars: self.contents.chars(),} } } struct TokenIter<'a> { chars: Chars<'a>,} struct Token; // represents some chunk of chars impl<'a> Iterator for TokenIter<'a> { type Item = Token; fn next(&mut self) -> Option<Self::Item> { self.chars.next(); // call as many times as necessary to create token Some(Token) // return created token here } } fn example(filename: String) { let file_contents = FileContents::new(filename); let tokens = file_contents.token_iter(); for token in tokens { // more processing here } } 路线:

Http4s

其中 val routes1:HttpRoutes[Task] = ??? val routes2:HttpRoutes[RTask] = ??? 只是带有自定义环境的 RTask

Task/RIO

可以通过引入“zio-cats-interop”库并做正则的type RTask[A] = RIO[Env,A] 来完成两个相同类型参数的路由的组合,但是由于routes1<+>routes1的类型参数是不变的,我可以'不要对不同的类型做同样的事情:

HttpRoutes

有什么解决办法吗?

解决方法

让我们处理一下事情:

type HttpRoutes[F[_]] = Http[OptionT[F,*],F]
type Http[F[_],G[_]] = Kleisli[F,Request[G],Response[G]]

所以您的 HttpRoutes[RTask] 实际上是 Kleisli[OptionT[RTask,Request[RTask],Response[RTask]]

假设您有 applyR: RTask ~> Task(应用 R)和 requireR: Task ~> RTask(添加不会使用的 R)。

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
}

您可以调整 Kleisli 的每一个:输入、输出、使用它们的效果,尽管这将是一件苦差事:

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]]
  }

您可以将上述逻辑提取到某个函数中,并将其应用于所有应从 RTask 转换为 Task 的路由。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...