We handle this as follows. I’m not sure it’s the best way but has worked for us for the last 3 years and hopefully gets you some of the way:
val versionRegex = """application/json;\s?version=(\d).*""".r
def versionFilter(route: ⇒ Route) =
headerValueByName("Accept") {
case versionRegex("1") ⇒ route
case versionRegex(other) ⇒ reject(
MalformedHeaderRejection("Accept", s"Unable to handle version $other"))
case _ ⇒ reject(
MalformedHeaderRejection("Accept", s"Accept must match $versionRegex"))
}
// When you setup the routes:
val versionedRoutes = versionFilter(routingSystem.routing)
I think once the request reach the route there is still something missing because the mediatype is seen as a custom one with a media parameter, there should be an extra marshaller for the custom mediatype pointing to the common json marshaller, but I haven’t found the right expression of this yet.
http http://localhost:8084/api Accept:application/json;version=1
HTTP/1.1 406 Not Acceptable
Content-Length: 76
Content-Type: text/plain; charset=UTF-8
Date: Wed, 02 May 2018 07:27:31 GMT
Server: akka-http/10.0.11
Resource representation is only available with these types:
application/json
In my case I can ignore the Accept header from the request.
But I’m not very happy about this solution, I would expect the Content Negotiator to be able to treat ‘application/json;version=1’ with the same marshaller of ‘application/json’ .