как связать тело запроса в Finch

Вот код для привязки параметра запроса к маршрутизатору.

val testReader: Endpoint[Test] = Endpoint.derive[Test].fromParams
val test: Endpoint[String] = post("test" ? testReader) { t : Test => {
    Created("OK")
  }}

Я использую метод fromParams. Этот метод может привязывать параметры запроса очень классным способом. Однако я не знаю, каким подобным образом я могу связать тело запроса в зяблике.

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


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


Ответы (1)


Чтобы предоставить полный рабочий пример, я возьму такой класс case:

case class Test(foo: Int, bar: String)

И такие просьбы:

import com.twitter.finagle.http.{ Method, Request, RequestBuilder }
import com.twitter.io.{ Buf, Reader }

val queryParamPost = Request(Method.Post, "/test?foo=1&bar=whatever")

val testJsonBuf = Buf.Utf8("""{ "foo": 1, "bar": "whatever" }""")

val bodyPost = RequestBuilder().url("http://localhost:8080/test").buildPost(testJsonBuf)

Теперь, когда вы пишете следующее…

import io.finch._

val testParams: Endpoint[Test] = Endpoint.derive[Test].fromParams
val test: Endpoint[Test] = post("test" ? testParams) { test: Test =>
  Created(test)
}

Что происходит, так это то, что Finch использует общий вывод (на основе Shapeless), чтобы определить (во время компиляции), как анализировать параметры запроса как Test. Затем вы можете протестировать конечную точку следующим образом:

import io.finch.circe._
import io.circe.generic.auto._

test.toService.apply(queryParamPost).onSuccess { response =>
  println(s"$response: ${ response.contentString }")
}

Который будет печатать:

Response("HTTP/1.1 Status(201)"): {"foo":1,"bar":"whatever"}

Здесь я использую общий вывод Circe для автоматического кодирования "созданного" Test как JSON для ответа. .

Вы также можете использовать Circe для получения считывателя тела запроса:

val testBody: Endpoint[Test] = body.as[Test]
val test2: Endpoint[Test] = post("test" :: testBody) { test: Test =>
  Created(test)
}

Это почти то же самое, что и test выше, но мы используем body, чтобы получить Endpoint[String], который будет читать тело запроса, а затем as, чтобы указать, что мы хотим, чтобы контент анализировался как JSON и декодировался как значение Test. Мы можем протестировать эту новую версию следующим образом:

test2.toService.apply(bodyPost).onSuccess { response =>
  println(s"$response: ${ response.contentString }")
}

И мы снова получим ожидаемый ответ.

Обычно, когда вы хотите прочитать информацию определенного типа о входящем запросе, вы будете использовать один из основных Endpoint, предоставляемых Finch (см. документы для получения более полного списка), а затем используйте такие методы, как as, map и т. д. для Endpoint, чтобы придать ему нужную форму.

person Travis Brown    schedule 01.05.2016
comment
Я не понял /, ? и :: на самом деле делают одно и то же :) - person Xiaohe Dong; 02.05.2016
comment
@Travis Brown Можете ли вы отредактировать свой ответ и добавить короткий пример с собственным декодером? В моем случае использования Test имеет поле типа scalaz.Maybe. Иметь его как Option работает, но как я могу заставить его работать с Maybe (который я предпочитаю Option по нескольким причинам)? Я продолжаю получать сообщение «Попытка декодировать значение неудачного курсора». - person slouc; 13.02.2017
comment
@slouc Это, вероятно, стоит нового вопроса (на который я был бы рад ответить). Я бы, вероятно, определил один общий экземпляр для scalaz.Maybe[A: Decoder], но мне нужно больше деталей. - person Travis Brown; 13.02.2017
comment
@ Трэвис Браун Да, я подумал, что это, вероятно, должен быть новый вопрос, но я был немного ленив. В любом случае, мне удалось решить это тем временем. Я разместил вопрос и ответил на него сам; не уверен, что администраторы SO считают это нормальным или нет, но если все в порядке, давайте сохраним это для других. Пожалуйста, не стесняйтесь добавлять что-то со своей стороны: stackoverflow.com/questions/42209195/ - person slouc; 13.02.2017