Акка-http: прием и обработка содержимого
Я пробовал Akka-http и, надеюсь, кто-то может пролить свет на следующие вопросы:
-
Как создать разные маршруты на основе заголовка accept: в запросе? Например, я хочу, чтобы один путь кода обрабатывал "json" и один обрабатывал запросы "xml" (по умолчанию "json", если отсутствует заголовок)
-
В случаях, когда я не хочу, чтобы тип contentType был выведен, как я его определяю? Например, в приведенном ниже коде я пытаюсь запустить json через compactPrint(), но это меняет его на строку, следовательно, "text/plain". Я хочу переопределить это и сказать клиенту, что он все еще json.
Мой код выглядит примерно так:
...
path("api") {
get {
complete {
getStuff.map[ToResponseMarshallable] {
case Right(r) if r.isEmpty => List[String]().toJson.compactPrint
case Right(r) => r.toJson.compactPrint
case Left(e) => BadRequest -> e
}
}
}
}
...
Ответ в этом случае является текстовым/открытым, так как compactPrint создает строку.
критика очень приветствуется.;)
Ответы
Ответ 1
Вы можете определить тип контента следующим образом:
complete {
HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`), """{"id":"1"}"""))
}
Вы можете создать свою собственную директиву как
def handleReq(json: String) = {
(get & extract(_.request.acceptedMediaRanges)) {
r =>
val encoding: MediaRange =
r.intersect(myEncodings).headOption
.getOrElse(MediaTypes.`application/json`)
complete {
// check conditions here
// HttpResponse(entity = HttpEntity(encoding.specimen, json)) //
}
}
}
и используйте директиву в маршруте как
val route = path("api"){ handleReq(json) }
Ответ 2
Потенциальный ответ на вопроС# 1, похоже, таков, но я хотел бы сделать это с помощью специальной директивы или, что-то более элегантного. К сожалению, документация для пользовательских директив Akka-Http, похоже, отсутствует.
// the encodings I want, in the order of preference
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))
...
path("api") {
(get & extract(_.request.acceptedMediaRanges)){
r =>
val encoding =
r.intersect(myEncodings).headOption
.getOrElse(MediaRange(`application/json`))
complete {
// check "encoding" here and make decision.
}
}
}
...
Надеясь, что кто-то может обеспечить что-то более чистое.
Ответ 3
Кажется, что принятый ответ больше не работает с akka-http v10.0.3.
Это работает, хотя:
// the encodings I want, in the order of preference
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))
...
path("api") {
(get & extract(_.request.headers)){ requestHeaders =>
val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders)
val encoding = mediaTypeNegotiator
.acceptedMediaRanges
.intersect(myEncodings)
.headOption
.getOrElse(MediaRange(`application/json`))
complete {
// check "encoding" here and make decision.
}
}
}
...
вы также можете сделать
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))
path("api") {
(get & extract(_.request.headers)){ requestHeaders =>
complete {
val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders)
if(mediaTypeNegotiator.accept(MediaTypes.`application/xml`)) {
// respond with xml
} else if(mediaTypeNegotiator.accept(MediaTypes.`application/json`)) {
// respond with json
} else {
// respond with json by default or reject properly :
reject(UnsupportedRequestContentTypeRejection(Set(MediaTypes.`application/xml`, MediaTypes.`application/json`)))
}
}
}
}
Надеется, что это поможет.