在Http4s API中将`Option[A]`转换为Ok()或NotFound()



我有一个API,它看起来像这样:

object Comics {
...
def impl[F[_]: Applicative]: Comics[F] = new Comics[F] {
def getAuthor(slug: Authors.Slug): F[Option[Authors.Author]] =
...

和一个看起来像这样的路由:

object Routes {
def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap {
case Some(author) => Ok(author)
case None         => NotFound()
}

因此,当存在None时,它会被转换为404。由于存在多个路由,.flatMap { ... }会被复制。

问题:如何将其移动到特定于我的项目的单独.orNotFound辅助函数中?


我的尝试:

为了让事情对我来说更简单(并避免最初在F上进行参数化(,我尝试在comicsRoutes:中定义它

def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
def orNotFound[A](opt: Option[A]): ???[A] =
opt match {
case Some(value) => Ok(value)
case None        => NotFound()
}
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap(orNotFound)

但这里的???是什么?它似乎不是ResponseStatus。此外,.flatMap { ... }是在import dsl._下制作的,但我想把它移得更远。什么是好地方?它是进入路由文件中,还是放入单独的ExtendedSomething扩展文件中?(我预计???Something可能有关联,但我有点困惑缺少的类型是什么。(

(同样重要的是,我如何找出这里的????我希望类型级别的???能给我一个"类型化的洞",而VSCode的悬停功能提供了非常零星的文档价值。(

Http4sDsl[F]为您的操作返回的类型为F[Response[F]]

它必须用F包装,因为您在F上使用.flatMap。CCD_ 21使用CCD_ 22进行参数化,因为它将使用F生成返回给调用者的结果。

要找到这一点,您可以使用IntelliJ,然后通过IDE生成注释(Alt+Enter,然后"将类型注释添加到值定义"(。您也可以:

  • 预览隐词以检查从Statusestrait导入的Ok对象是否提供了具有http4sOkSyntax隐式转换的扩展方法(Ctrl+Alt+Shift+加号,您可以按几次以进一步扩展隐词,Ctrl+Alt+Shift+Minut可再次隐藏隐词(
  • 按Shift键两次打开查找窗口,再按两次包含非投影符号,即可查找http4sOkSyntax
  • 从那里用Ctrl+B导航OkOpsEntityResponseGenerator类,该类为您提供您(在apply中(使用的返回F[Resposne[F]]的功能

因此,如果您想四处移动/提取它们,请注意实例化DSL和扩展方法需要哪些隐含器。

(Mac操作系统(有时使用Cmd而不是Ctrl(和非Mac操作系统之间的快捷方式不同,所以如果您有问题,只需在文档中查看即可(。

多亏了Mateusz,我才知道???应该是F[Response[F]]

为了使这个助手功能完全工作,又出现了两个与类型相关的问题:

  1. 由于value: A是多态的,Http4s需要一个隐式EntityEncoder[F, A]来序列化任意值。(这与最初的{ case ... }匹配没有问题,因为类型是具体的,而不是多态的

  2. 出于某种原因,添加这个隐式注释是不够的。执行.flatMap(orNotFound)会使类型推断失败。执行.flatMap(orNotFound[Authors.Slug])修复了此问题。

(感谢keynmol指出了另外两个。(

有了这三个变化,这导致:

def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
def orNotFound[A](opt: Option[A])(implicit ee: EntityEncoder[F, A]): F[Response[F]] =
opt match {
case Some(value) => Ok(value)
case None        => NotFound()
}
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap(orNotFound[Authors.Author])
...

相关内容

  • 没有找到相关文章

最新更新