Skip to content

Versioning via the Query String

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

The initial version of a controller may not have any API version attribution and will implicitly become the configured default API version. The default configuration uses the value 1.0.

ASP.NET Web API

[RoutePrefix( "api/helloworld" )]
public class HelloWorldController : ApiController
{
    [Route]
    public string Get() => "Hello world!";
}

ASP.NET Web API and OData

[ODataRoutePrefix( "People" )]
public class PeopleController : ODataController
{
    [ODataRoute]
    public IHttpActionResult Get( ODataQueryOptions<Person> options ) =>
        Ok( new[]{ new Person() } );
}

ASP.NET Core with MVC (Core)

[ApiController]
[Route( "api/[controller]" )]
public class HelloWorldController : ControllerBase
{
    [HttpGet]
    public string Get() => "Hello world!";
}

ASP.NET Core and OData

public class PeopleController : ODataController
{
    [HttpGet]
    public IHttpActionResult Get( ODataQueryOptions<Person> options ) =>
        Ok( new[]{ new Person() } );
}

To create the next version of the controller, you can choose to create a new controller with the same route, but decorated it as API version 2.0. For example:

ASP.NET Web API

[ApiVersion( 2.0 )]
[RoutePrefix( "api/helloworld" )]
public class HelloWorldController : ApiController
{
    [Route]
    public string Get() => "Hello world!";
}

ASP.NET Web API and OData

[ApiVersion( 2.0 )]
[ControllerName( "People" )]
[ODataRoutePrefix( "People" )]
public class People2Controller : ODataController
{
    [ODataRoute]
    public IHttpActionResult Get( ODataQueryOptions<Person> options ) =>
        Ok( new[]{ new Person() } );
}

ASP.NET Core with MVC (Core)

[ApiVersion( 2.0 )]
[ApiController]
[Route( "api/helloworld" )]
public class HelloWorld2Controller : ControllerBase
{
    [HttpGet]
    public string Get() => "Hello world!";
}

ASP.NET Core and OData

[ApiVersion( 2.0 )]
[ControllerName( "People" )]
public class People2Controller : ODataController
{
    [HttpGet]
    public IHttpActionResult Get( ODataQueryOptions<Person> options ) =>
        Ok( new[]{ new Person() } );
}

The effect of this attribution is that the following requests match different controller implementations:

Request URL Matched Controller
/api/helloworld?api-version=1.0 HelloWorldController
/api/helloworld?api-version=2.0 HelloWorld2Controller
/api/People?api-version=1.0 PeopleController
/api/People?api-version=2.0 People2Controller

It’s important to note that only an undecorated controller will be inferred as the configured, default API version. Once a controller has any API version attribution, it will never be considered as the default API version again unless the API version attribute includes the default API version. This allows you permanently remove API versions over time.

ASP.NET Core with Minimal APIs

var builder = WebApplication.CreateBuilder( args );

builder.Services.AddProblemDetails();
builder.Services.AddApiVersioning();

var app = builder.Build();
var hello = app.NewVersionedApi();
var v1 = hello.MapGroup( "/helloworld" ).HasApiVersion( 1.0 );
var v2 = hello.MapGroup( "/helloworld" ).HasApiVersion( 2.0 );

v1.MapGet( "/", () => "Hello world!" );
v2.MapGet( "/", () => "Hello world!" );

app.Run();
Clone this wiki locally