Skip to content

Version Advertisement

Chris Martinez edited this page Dec 29, 2022 · 7 revisions

Splitting implemented service API versions across hosted applications or endpoints is a fairly common scenario. There are several reasons why you might choose to split hosted endpoints, such as different run-time versions or traffic load balancing.

When service API versions are split across deployments, two issues arise:

  1. The correct service API version cannot be selected across deployments.
  2. The set of implemented service API versions cannot be aggregated across deployments.

Service Gateway

The first issue can be remedied by a using a service gateway. The gateway becomes responsible for obfuscating which endpoints host which API versions. The exact method in which gateways implement this functionality is at the discretion of service authors.

Future consideration is being investigated to support YARP.

Service API Version Advertisement

Since there is no direct way to know or interrogate the available API version information at run-time in a performant manner when services are deployed separately, an alternate approach is required. This concept is referred to as service API version advertisement. Each service will advertise the supported and deprecated API versions it knows about.

A service can advertise its supported and deprecated API versions using the AdvertiseApiVersionsAttribute. This attribute functions almost identically to the ApiVersionAttribute, except that it is never considered for controller resolution and cannot be applied to an action. The advertised and implemented API versions are always aggregated together.

The following is an example of a service with API version 2.0 hosted at another endpoint that knows that API version 1.0 is a supported version somewhere else:

[ApiVersion( 2.0 )]
[AdvertiseApiVersions( 1.0 )]
[ApiController]
[Route( "api/[controller]" )]
public class HelloWorld2Controller : ControllerBase
{
    [HttpGet]
    public string Get() => "Hello world v2.0!" );
}
[ApiVersion( 2.0 )]
[AdvertiseApiVersions( 1.0 )]
[ApiController]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : ControllerBase
{
    [HttpGet]
    public string Get() => "Hello world v2.0!" );
}

This service implementation will now advertise that API version 1.0 and 2.0 are supported through the api-supported-version HTTP header even though it has no knowledge about where API version 1.0 is. In a similar fashion, a service can also advertise deprecated API versions. Note that the ApiVersioningOptions.ReportApiVersions must be enabled for the HTTP headers to be returned in responses.

The only drawback to this approach is that each implementation needs to be updated with the supported and deprecated API versions when new API versions are released. One possible solution to this limitation is to create an IApiVersionProvider attribute that reads the advertised API versions from a configuration source such as a file or database. If this is still undesirable, then there is still the option of using HTTP header injection by the host server or another mechanism to send the supported and deprecated API version information.

Mixing Minimal APIs with Controllers

Applies to ASP.NET Core only

Mixing existing controller-based APIs with Minimal APIs is a supported scenario, but the collation of API versions is broken by default. This is simply because there is no intrinsic way to group controllers and Minimal APIs together. However, by advertising API versions across implementations with the same name, the correct collation is possible.

[ApiVersion( 1.0 )]
[AdvertiseApiVersions( 2.0 )]
[ApiController]
[Route( "api/[controller]" )]
public class HelloWorld2Controller : ControllerBase
{
    [HttpGet]
    public string Get() => "Hello world v1.0!" );
}

Figure 1: the controller-based API in 1.0

var hello = app.NewVersionedApi();

hello.MapGet( "/api/helloworld", () => "Hello world v2.0!" )
     .HasApiVersion( 2.0 )
     .AdvertisesApiVersion( 1.0 );

Figure 1: a minimal API in 2.0

When ApiVersioningOptions.ReportApiVersions is enabled the controller and Minimal API implementations will both return api-supported-versions: 1.0, 2.0.

Clone this wiki locally