I'm trying out Akka-http and hopefully someone can shed light on a the following questions:
How does one create different routes based on the accept: header in the request? For example, i want one code path to handle "json" and one to handle "xml" requests (with default to "json" if header is missing)
In cases where I don't want the contentType to be inferred, how do i specify it? For example, in the code below I try to run the json through compactPrint() but this changes it to a string, hence "text/plain". I want to override that and tell the client it's still json.
My code is something like this;
...
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
}
}
}
}
...
The response in this case is text/plain, since compactPrint creates a string.
criticism very welcome. ;)
You can define Content Type as follows,
complete {
HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`), """{"id":"1"}"""))
}
You can create your custom directive as,
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)) //
}
}
}
and use the directive in route as
val route = path("api"){ handleReq(json) }
A potential answer for question #1 seems to be this, but I'd like to do it via a custom directive or or something more elegant. Unfortunately the documentation for Akka-Http custom directives seems to be missing.
// 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.
}
}
}
...
Hoping someone can provide something cleaner.
It seems that the accepted answer doesn't work anymore with akka-http v10.0.3.
This works though :
// 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.
}
}
}
...
you could also do
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`)))
}
}
}
}
Hopes this helps.