[英]Converting an `Option[A]` to an Ok() or NotFound() inside an Http4s API
我有一個看起來像這樣的 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
助手 function 中?
我的嘗試:
為了使事情對我來說簡單(並避免最初對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)
但是是什么???
這里? 它似乎不是Response
或Status
。 此外, .flatMap {... }
是在import dsl._
下制作的,但我想把它移到更遠的地方。 什么是好地方? 將它 go 放入路由文件中,還是將其放入單獨的ExtendedSomething
擴展文件中? (我希望???
和Something
可能相關,但我對缺少的類型有點困惑。)
(同樣重要的是,我如何找出???
在這里?我希望???
在類型級別上可能會給我一個“類型漏洞”,而 VSCode 的 hover function 提供了非常零星的文檔價值。)
Http4sDsl[F]
為您的操作返回的類型是F[Response[F]]
。
它必須用F
包裝,因為您在F
上使用.flatMap
。 Response
使用F
參數化,因為它將產生使用F
返回給調用者的結果。
要找出這一點,您可以使用 IntelliJ,然后通過 IDE 生成注釋(Alt+Enter,然后“將類型注釋添加到值定義”)。 你也可以:
Statuses
trait 導入的Ok
object 是否提供了具有http4sOkSyntax
隱式轉換的擴展方法(Ctrl+Alt+Shift+加號,您可以按幾次以擴展隱式更多,Ctrl+Alt+Shift+Minut 到再次隱藏它們)http4sOkSyntax
找到window,然后再次按兩次以包含非項目符號,OkOps
導航到EntityResponseGenerator
class ,它為您提供您使用的功能(在apply
中)返回F[Resposne[F]]
。因此,如果您想移動/提取它們,請注意實例化 DSL 和擴展方法所需的隱式。
(Mac OS 之間的快捷方式不同 - 有時使用 Cmd 而不是 Ctrl - 和非 Mac OS 系統,因此如果您有問題,只需在文檔中檢查它們)。
感謝Mateusz,我知道了???
應該是F[Response[F]]
。
為了讓這個助手 function 充分工作,又出現了兩個與類型相關的問題:
由於value: A
是多態的,Http4s 需要一個隱式的EntityEncoder[F, A]
來序列化任意值。 (這不是原始{ case... }
匹配的問題,因為類型是具體的而不是多態的。
由於某種原因,添加這個隱式注釋是不夠的。 執行.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])
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.