Почему Finch использует EndPoint для представления маршрутизатора, параметра запроса и тела запроса

В 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 не найденная страница. Хотя я ожидаю, что ошибка должна сообщаться раньше, как ошибка компиляции. Интересно, это конструктивный недостаток или это на самом деле зяблик пытается исправить?

Спасибо заранее


person Xiaohe Dong    schedule 02.05.2016    source источник


Ответы (1)


Прежде всего, большое спасибо, что спросили об этом!

Позвольте мне дать вам некоторое представление о том, как работают конечные точки Finch. Если вы говорите о теории категорий, Endpoint — это Applicative вложение StateT, представленное как нечто близкое к Input => Option[(Input, A)].

Проще говоря, конечная точка принимает Input, который упаковывает HTTP-запрос, а также фиксирует текущий путь (например: /foo/bar/baz). Когда конечная точка применяется к заданному запросу и либо соответствует ему (возвращается Some), либо не работает (возвращается None). При совпадении он изменяет состояние Input, обычно удаляя из него первый сегмент пути (например, удаляя foo из /foo/bar/baz), чтобы следующей конечной точкой была цепочка, которая может работать с новым Input (и новым путем).

После сопоставления конечной точки Финч проверяет, не осталось ли в 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"), путь не изменяется. Это просто означает, что единственный способ обслуживать конечную точку строки запроса (примечание: конечная точка, которая извлекает только параметры строки запроса) — отправить ей запрос с пустым путем /.

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)")
person Vladimir Kostyukov    schedule 02.05.2016