Параметры запроса для запросов GET с использованием Akka HTTP (ранее известного как Spray)

Одной из особенностей Akka HTTP (ранее известного как Spray) является его способность автоматически сортировать и демаршалировать данные туда и обратно из json в классы case и т. д. Мне удалось заставить это хорошо работать.

На данный момент я пытаюсь сделать HTTP-клиент, который выполняет запрос GET с параметрами запроса. В настоящее время код выглядит так:

val httpResponse: Future[HttpResponse] =
  Http().singleRequest(HttpRequest(
    uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/""" +
          s"query?seq=${seq}" +
          s"&max-mismatches=${maxMismatches}" +
          s"&pam-policy=${pamPolicy}"))

Ну, это не так красиво. Было бы неплохо, если бы я мог просто передать класс case, содержащий параметры запроса, и заставить Akka HTTP автоматически генерировать параметры запроса, как это делается для json. (Кроме того, серверная сторона Akka HTTP имеет несколько элегантный способ анализа параметров запроса GET, поэтому можно подумать, что у него также будет несколько элегантный способ их генерации.)

Я хотел бы сделать что-то вроде следующего:

val httpResponse: Future[HttpResponse] =
  Http().singleRequest(HttpRequest(
    uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/query""",
    entity = QueryParams(seq = seq, maxMismatches = maxMismatches, pamPolicy = pamPolicy)))

Только вышеизложенное на самом деле не работает.

Выполнимо ли то, что я хочу, с помощью Akka HTTP? Или мне просто нужно делать все по старинке? То есть явно сгенерировать параметры запроса, как я делаю в первом блоке кода выше.

(Я знаю, что если бы я изменил это с GET на POST, я, вероятно, мог бы заставить его работать так, как мне бы хотелось, чтобы он работал, так как тогда я мог бы автоматически преобразовать содержимое запроса POST из случая класс в json, но я действительно не хочу этого делать здесь.)


person Douglas    schedule 10.08.2015    source источник


Ответы (2)


Вы можете использовать класс Uri, чтобы делать то, что хотите. Он предлагает несколько способов получить набор параметров в строке запроса с помощью метода withQuery. Например, вы можете сделать что-то вроде этого:

val params = Map("foo" -> "bar", "hello" -> "world")
HttpRequest(Uri(hostAndPath).withQuery(params))

Or

HttpRequest(Uri(hostAndPath).withQuery(("foo" -> "bar"), ("hello" -> "world")))
person cmbaxter    schedule 11.08.2015
comment
Преимущество использования этого метода заключается в том, что экранирование будет выполняться автоматически с использованием этого метода. - person jrudolph; 11.08.2015
comment
С Akka-http 2.4.8 это, кажется, нуждается в обертке Query: .withQuery(Query(params))) - person akauppi; 20.07.2016
comment
Это должно быть в документации - person coolboyjules; 30.05.2018
comment
@coolboyjules точно. Этот ответ отличный, но жаль, что нужно так много искать в Интернете, прежде чем приземлиться здесь. Это относится к документации. В моем списке дел — так как код для документации с открытым исходным кодом. - person Niks; 04.11.2020
comment
И теперь это часть документации :) https://doc.akka.io/docs/akka-http/10.2/client-side/request-and-response.html, который связан с конкретным примером здесь https://doc.akka.io/docs/akka-http/10.2/common/uri-model.html#query-string-in-uri - person Niks; 05.01.2021

Очевидно, это можно сделать, изменив расширение возможностей Akka HTTP, но для того, что вам нужно (просто более аккуратный способ построения строки запроса), вы можете сделать это с помощью некоторого удовольствия от scala:

type QueryParams = Map[String, String]

object QueryParams {

  def apply(tuples: (String, String)*): QueryParams = Map(tuples:_*)
}

implicit class QueryParamExtensions(q: QueryParams) {

  def toQueryString = "?"+q.map{
    case (key,value) => s"$key=$value" //Need to do URL escaping here?
  }.mkString("&")
}

implicit class StringQueryExtensions(url: String) {
  def withParams(q: QueryParams) =
    url + q.toQueryString
}

val params = QueryParams(
  "abc" -> "def",
  "xyz" -> "qrs"
)

params.toQueryString // gives ?abc=def&xyz=qrs

"http://www.google.com".withParams(params) // gives http://www.google.com?abc=def&xyz=qrs
person mattinbits    schedule 11.08.2015