Content Negotiation in JAX-RS allows you to leverage the information in the client requests Accept
header to map that request to a specific handler-method within your application. In combination with vendor-specific media types this approach can be used for versioning of an API.
So, the idea is to introduce our own, custom media type - a so called vendor-specific media types and use that to dispatch clients requests to the proper method.
A vendor-specific media type starts with a vnd.
-prefix for its subtype-name - the rest of the subtype is up to you. So the following are valid vendor-types:
application/vnd.my.comp+xml
application/vnd.schoeffm+json
By appending the +xml
or +json
-suffix we give the caller a hint what representation it can actually expect in the respective response.
Another feature of media types is that they can bear parameters - normally used to express precedence - which could be used for requesting a specific version:
Accept: application/vnd.schoeffm+json;version=1.0
Although this looks perfect for versioning it doesn’t work in practice since the parameter is optional. So when used in declarative method-mapping via @Produces
the media-type is still application/vnd.schoeffm+json
(without version parameter). Thus, if you have several, parallel implementations for an endpoint just differing in the version-attribute of the javax.ws.rs.Produces
annotation the server will throw an exception at startup since it cannot distinguish ‘em.It’d still be possible to do this using i.e. javax.ws.rs.core.Variant
, but this approach seemed just too cumbersome to be used..
Therefore we’ve modelled the version-information into the actual subtype-name (see this Github-repo)
@GET
@Produces("application/vnd.schoeffm-v1+json")
public Response customersOld() { return Response.ok("Version 1.0").build(); }
@GET
@Produces("application/vnd.schoeffm-v2+json")
public Response customersNew() { return Response.ok("Version 2.0").build(); }
Which allows us to:
- have several versions of an API exposed at the same time
- several media-types map to one method (allowing i.e. fallbacks to always server
latest
) - stable URIs for resources (so the resource doesn’t change with every new version)