在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 ,参数应具有名称和年龄。 (router :: requestParameters
)
但是,我仍然可以运行无效端点,该端点不会成功包含任何请求路径(实际上没有编译错误)
Await.ready(Http.serve(":3000", requestParameters.toService))
结果是返回404未找到的页面。即使我希望错误应该像编译错误一样早先报告。我想知道这是一个设计上的缺点还是实际上是试图修复?
非常感谢提前
答案 0 :(得分:2)
首先,非常感谢您提出这个问题!
让我介绍一下芬奇的终端是如何运作的。如果您说类别理论,则Endpoint
是Applicative
嵌入StateT
,表示为接近Input => Option[(Input, A)]
的内容。
简单来说,端点采用Input
包装HTTP请求并捕获当前路径(例如:/foo/bar/baz
)。将端点应用于给定请求时,匹配(返回Some
)或覆盖(返回None
)。匹配时,它会更改Input
的状态,通常会从中删除第一个路径段(例如:从foo
中移除/foo/bar/baz
),以便下一个端点可以使用链接新Input
(和新路径)。
匹配端点后,Finch会检查Input
中是否还有其他内容未匹配。如果遗漏了某些内容,则认为该匹配失败,您的服务返回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)
当涉及匹配/提取查询字符串参数的端点时,那里没有触及路径段,并且状态将不变地传递给下一个端点。因此,当应用端点param("foo")
时,路径不受影响。这只是意味着,提供查询字符串端点的唯一方法(注意:只提取查询字符串参数的端点)是向它发送一个空路径为/
的请求。< / p>
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)")