为什么Finch使用EndPoint来表示路由器,请求参数和请求主体

时间:2016-05-02 00:51:37

标签: web-services scala finagle finch

在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未找到的页面。即使我希望错误应该像编译错误一样早先报告。我想知道这是一个设计上的缺点还是实际上是试图修复?

非常感谢提前

1 个答案:

答案 0 :(得分:2)

首先,非常感谢您提出这个问题!

让我介绍一下芬奇的终端是如何运作的。如果您说类别理论,则EndpointApplicative嵌入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)")