6.17 API Versioning
Since 1.1.x, Micronaut supports API versioning via a dedicated @Version annotation.
The following example demonstrates how to version an API:
Versioning an API
import io.micronaut.core.version.annotation.Version;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
@Controller("/versioned")
class VersionedController {
@Version("1") (1)
@Get("/hello")
String helloV1() {
return "helloV1";
}
@Version("2") (2)
@Get("/hello")
String helloV2() {
return "helloV2";
}
Versioning an API
import io.micronaut.core.version.annotation.Version
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
@Controller("/versioned")
class VersionedController {
@Version("1") (1)
@Get("/hello")
String helloV1() {
"helloV1"
}
@Version("2") (2)
@Get("/hello")
String helloV2() {
"helloV2"
}
Versioning an API
import io.micronaut.core.version.annotation.Version
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
@Controller("/versioned")
internal class VersionedController {
@Version("1") (1)
@Get("/hello")
fun helloV1(): String {
return "helloV1"
}
@Version("2") (2)
@Get("/hello")
fun helloV2(): String {
return "helloV2"
}
1 | The helloV1 method is declared as version 1 |
2 | The helloV2 method is declared as version 2 |
You should then enabling versioning by setting micronaut.router.versioning.enabled
to true
in application.yml
:
Enabling Versioning
micronaut:
router:
versioning:
enabled: true
By default Micronaut has 2 out-of-the-box strategies for resolving the version that are based on an HTTP header named X-API-VERSION
or a request parameter named api-version
, however this is configurable. A full configuration example can be seen below:
Configuring Versioning
micronaut:
router:
versioning:
enabled: true (1)
parameter:
enabled: false (2)
names: 'v,api-version' (3)
header:
enabled: true (4)
names: (5)
- 'X-API-VERSION'
- 'Accept-Version'
1 | Enables versioning |
2 | Enables or disables parameter based versioning |
3 | Specify the parameter names as a comma separated list |
4 | Enables or disables header based versioning |
5 | Specify the header names as a YAML list |
If this is not enough you can also implement the RequestVersionResolver interface which receives the HttpRequest and can implement any strategy you choose.
Default Version
It is possible to supply a default version through configuration.
Configuring Default Version
micronaut:
router:
versioning:
enabled: true
default-version: 3 (1)
1 | Sets the default version |
A route will not be matched if the following conditions are met:
The default version is configured
No version is found in the request
The route defines a version
The route version does not match the default version
If the incoming request specifies a version then the default version has no effect.
Versioning Client Requests
Micronaut’s Declarative HTTP client also supports automatic versioning of outgoing requests via the @Version annotation.
By default if you annotate a client interface with @Version the value supplied to the annotation will be included using the X-API-VERSION
header.
For example:
import io.micronaut.core.version.annotation.Version;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.client.annotation.Client;
import io.reactivex.Single;
@Client("/hello")
@Version("1") (1)
public interface HelloClient {
@Get("/greeting/{name}")
String sayHello(String name);
@Version("2")
@Get("/greeting/{name}")
Single<String> sayHelloTwo(String name); (2)
}
import io.micronaut.core.version.annotation.Version
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client
import io.reactivex.Single
@Client("/hello")
@Version("1") (1)
interface HelloClient {
@Get("/greeting/{name}")
String sayHello(String name)
@Version("2")
@Get("/greeting/{name}")
Single<String> sayHelloTwo(String name) (2)
}
import io.micronaut.core.version.annotation.Version
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client
import io.reactivex.Single
@Client("/hello")
@Version("1") (1)
interface HelloClient {
@Get("/greeting/{name}")
fun sayHello(name : String) : String
@Version("2")
@Get("/greeting/{name}")
fun sayHelloTwo(name : String) : Single<String> (2)
}
1 | The @Version can be used as the type level to specify the version to use for all methods |
2 | When defined at the method level it is used only for that method |
The default behaviour for how the version is sent for each call can be configured with DefaultClientVersioningConfiguration:
Property | Type | Description |
---|---|---|
| java.util.List | The list of request header names. |
| java.util.List | The list of request query parameter names. |
For example to use Accept-Version
as the header name:
Configuring Client Versioning
micronaut:
http:
client:
versioning:
default:
headers:
- 'Accept-Version'
- 'X-API-VERSION'
The default
key is used to refer to the default configuration. You can specify client specific configuration by using the value passed to @Client
(typically the service ID). For example:
Configuring Versioning
micronaut:
http:
client:
versioning:
greeting-service:
headers:
- 'Accept-Version'
- 'X-API-VERSION'
The above uses a key called greeting-service
which can be used to configure a client annotated with @Client('greeting-service')
.