Using the Accept Header to version your API

Hi all,

I’m busy with migrating an API from Spray.io to akka-http.

We are using the Accept header in the request also to request for a particular version of the api. Example = Accept:“application/json; version=1”.

But currently with such requests we get the following responses:

Resource representation is only available with these types:
application/json

I was trying to handle this by creating a custom media type but it’s not working.

  val `application/json(v1)` = MediaType.customWithFixedCharset("application", "json", HttpCharsets.`UTF-8`, params = Map("version" -> "1"))
  val parserSettings = ParserSettings(system).withCustomMediaTypes(`application/json(v1)`)
  val serverSettings = ServerSettings(system).withParserSettings(parserSettings)

  def start(routingSystem: RoutingSystem): Future[ServerBinding] = {
    Http(system).bindAndHandle(routingSystem.routing, interface, defaultHttpPort, settings = serverSettings)
  }

Any ideas or reference on how to handle this?

Thanks in advance

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)

Hi Julian,

Thanks for the quick reaction.

I tried in this way but I still get the HTTP 406.

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

Maybe it can be useful for other users.

I solved this by using the method withAcceptAll .

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’ .

Any thoughts?