为什么Finch用EndPoint来表示Router、Request Parameter和Request Body
Why Finch using EndPoint to represent Router, Request Parameter and Request Body
在finch中,我们可以这样定义路由、请求参数、请求体。
case class Test(name: String, age: Int)
val router: Endpoint[Test] = post("hello") { Ok(Test("name", 30)) }
val requestBody: Endpoint[Test] = body.as[Test]
val requestParameters: Endpoint[Test] = Endpoint.derive[Test].fromParams
好处是我们可以一起组合EndPoint。例如,我可以定义:
请求路径为hello and Parameter should have name and 年龄。 (router :: requestParameters
)
但是,我仍然可以运行一个无效端点,它不包含任何请求路径成功(实际上没有编译错误)
Await.ready(Http.serve(":3000", requestParameters.toService))
结果返回 404 未找到页面。即使我希望错误应该像编译错误一样早点报告。我想知道这是设计缺陷还是实际上是 finch 试图修复的?
非常感谢
首先,非常感谢您提出这个问题!
让我向您介绍一下 Finch 端点的工作原理。如果你讲范畴论,Endpoint
是一个 Applicative
嵌入 StateT
表示为接近 Input => Option[(Input, A)]
.
的东西
简单地说,一个端点采用 Input
包装 HTTP 请求,并捕获 当前路径 (例如:/foo/bar/baz
)。当端点应用于给定请求并且匹配它(返回Some
)或失败(返回None
).匹配时,它会更改 Input
的状态,通常会从中删除第一个路径段(例如:从 /foo/bar/baz
中删除 foo
),因此下一个端点是链可以使用新 Input
(和新路径)。
一旦端点匹配,Finch 会检查 Input
中是否还有其他不匹配的内容。如果有遗漏,则认为匹配不成功,您的服务 returns 404.
scala> val e = "foo" :: "bar"
e: io.finch.Endpoint[shapeless.HNil] = foo/bar
scala> e(Input(Request("/foo/bar/baz"))).get._1.path
res1: Seq[String] = List(baz)
当涉及到端点 matching/extracting 查询字符串参数时,那里没有路径段被触及,状态被传递到下一个端点不变。因此,当应用端点 param("foo")
时,路径不受影响。这只是意味着,服务查询字符串端点(注意:仅提取查询字符串参数的端点)的唯一方法是向它发送空路径请求/
.
scala> val s = param("foo").toService
s: com.twitter.finagle.Service[com.twitter.finagle.http.Request,com.twitter.finagle.http.Response] = <function1>
scala> s(Request("/", "foo" -> "bar")).get
res4: com.twitter.finagle.http.Response = Response("HTTP/1.1 Status(200)")
scala> s(Request("/bar", "foo" -> "bar")).get
res5: com.twitter.finagle.http.Response = Response("HTTP/1.1 Status(404)")
在finch中,我们可以这样定义路由、请求参数、请求体。
case class Test(name: String, age: Int)
val router: Endpoint[Test] = post("hello") { Ok(Test("name", 30)) }
val requestBody: Endpoint[Test] = body.as[Test]
val requestParameters: Endpoint[Test] = Endpoint.derive[Test].fromParams
好处是我们可以一起组合EndPoint。例如,我可以定义:
请求路径为hello and Parameter should have name and 年龄。 (router :: requestParameters
)
但是,我仍然可以运行一个无效端点,它不包含任何请求路径成功(实际上没有编译错误)
Await.ready(Http.serve(":3000", requestParameters.toService))
结果返回 404 未找到页面。即使我希望错误应该像编译错误一样早点报告。我想知道这是设计缺陷还是实际上是 finch 试图修复的?
非常感谢
首先,非常感谢您提出这个问题!
让我向您介绍一下 Finch 端点的工作原理。如果你讲范畴论,Endpoint
是一个 Applicative
嵌入 StateT
表示为接近 Input => Option[(Input, A)]
.
简单地说,一个端点采用 Input
包装 HTTP 请求,并捕获 当前路径 (例如:/foo/bar/baz
)。当端点应用于给定请求并且匹配它(返回Some
)或失败(返回None
).匹配时,它会更改 Input
的状态,通常会从中删除第一个路径段(例如:从 /foo/bar/baz
中删除 foo
),因此下一个端点是链可以使用新 Input
(和新路径)。
一旦端点匹配,Finch 会检查 Input
中是否还有其他不匹配的内容。如果有遗漏,则认为匹配不成功,您的服务 returns 404.
scala> val e = "foo" :: "bar"
e: io.finch.Endpoint[shapeless.HNil] = foo/bar
scala> e(Input(Request("/foo/bar/baz"))).get._1.path
res1: Seq[String] = List(baz)
当涉及到端点 matching/extracting 查询字符串参数时,那里没有路径段被触及,状态被传递到下一个端点不变。因此,当应用端点 param("foo")
时,路径不受影响。这只是意味着,服务查询字符串端点(注意:仅提取查询字符串参数的端点)的唯一方法是向它发送空路径请求/
.
scala> val s = param("foo").toService
s: com.twitter.finagle.Service[com.twitter.finagle.http.Request,com.twitter.finagle.http.Response] = <function1>
scala> s(Request("/", "foo" -> "bar")).get
res4: com.twitter.finagle.http.Response = Response("HTTP/1.1 Status(200)")
scala> s(Request("/bar", "foo" -> "bar")).get
res5: com.twitter.finagle.http.Response = Response("HTTP/1.1 Status(404)")