Skip to content

Existing Services Quick Start

Chris Martinez edited this page Jan 23, 2019 · 8 revisions

While it's great to plan for an API versioning story for your services upfront, it's all too common to need API versioning after your services are in production. The ASP.NET versioning libraries provide features to help you retrofit existing services and integrate formal API versioning without breaking your existing clients.

Unless a service is API version-neutral, existing services have some logical, yet undefined, API version that is not formally declared by the service or known to a client. In order to prevent existing clients from breaking, they must be able to make requests to the original URL without specifying any API version information.

When API versioning is applied, all of the existing services now have an explicit API version on the service side. The initial, default API version is 1.0, but that can be configured to be a different API version. All existing controller definitions that do not have explicit API version definitions will now be implicitly bound to the default API version. Once a controller has any API version attribution or conventions, it will never be implicitly matched. This enables service authors to permanently sunset API versions over time. Controllers that have an implicit API version can be confusing to service authors; especially, in a team environment. It is recommended that you explicitly apply API versions to all of your existing services when you introduce formal API versioning.

ASP.NET Web API

public static class WebApiConfig
{
    public static void Configuration( HttpConfiguration configuration )
    {
        // allow a client to call you without specifying an api version
        // since we haven't configured it otherwise, the assumed api version will be 1.0
        configuration.AddApiVersioning( o => o.AssumeDefaultVersionWhenUnspecified = true );

        // remaining configuration omitted for brevity
    }
}

[ApiVersion( "1.0" )] // this attribute isn't required, but it's easier to understand
[RoutePrefix( "people" )]
public class PeopleController : ApiController
{
    // GET ~/people
    // GET ~/people?api-version=1.0
    [Route]
    public IHttpActionResult Get() => Ok( new[] { new Person() } );
}

[ApiVersion( "2.0" )]
[RoutePrefix( "people" )]
public class People2Controller : ApiController
{
    // GET ~/people?api-version=2.0
    [Route]
    public IHttpActionResult Get() => Ok( new[] { new Person() } );
}

ASP.NET Web API with OData v4.0

public static class WebApiConfig
{
    public static void Configuration( HttpConfiguration configuration )
    {
        // allow a client to call you without specifying an api version
        // since we haven't configured it otherwise, the assumed api version will be 1.0
        configuration.AddApiVersioning( o => o.AssumeDefaultVersionWhenUnspecified = true );

        var modelBuilder = new VersionedODataModelBuilder( configuration )
        {
            DefaultModelConfiguration = ( builder, apiVersion ) =>
            {
                builder.EntitySet<Person>( "People" );
            }
        };
        var models = modelBuilder.GetEdmModels();

        configuration.MapVersionedODataRoutes( "odata", null, models );

        // remaining configuration omitted for brevity
    }
}

[ApiVersion( "1.0" )] // this attribute isn't required, but it's easier to understand
[ODataRoutePrefix( "People" )]
public class PeopleController : ODataController
{
    // GET ~/people
    // GET ~/people?api-version=1.0
    [ODataRoute]
    public IHttpActionResult Get() => Ok( new[] { new Person() } );
}

[ApiVersion( "2.0" )]
[ControllerName( "People" )]
[ODataRoutePrefix( "People" )]
public class People2Controller : ODataController
{
    // GET ~/people?api-version=2.0
    [ODataRoute]
    public IHttpActionResult Get() => Ok( new[] { new Person() } );
}

ASP.NET Core

public class Startup
{
    public void ConfigureServices( IServiceCollection services )
    {
        services.AddMvc();

        // allow a client to call you without specifying an api version
        // since we haven't configured it otherwise, the assumed api version will be 1.0
        services.AddApiVersioning( o => o.AssumeDefaultVersionWhenUnspecified = true );

        // remaining configuration omitted for brevity
    }
}

[ApiVersion( "1.0" )] // this attribute isn't required, but it's easier to understand
[ApiController]
[Route( "[controller]" )]
public class PeopleController : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok( new[] { new Person() } );
}

[ApiVersion( "2.0" )]
[ApiController]
[Route( "people" )]
public class People2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok( new[] { new Person() } );
}

ASP.NET Core with OData v4.0

public class Startup
{
    public void ConfigureServices( IServiceCollection services )
    {
        services.AddMvc();

        // allow a client to call you without specifying an api version
        // since we haven't configured it otherwise, the assumed api version will be 1.0
        services.AddApiVersioning( o => o.AssumeDefaultVersionWhenUnspecified = true );
        services.AddOData().EnableApiVersioning();

        // remaining configuration omitted for brevity
    }

    public void Configure( IApplicationBuilder app, VersionedODataModelBuilder modelBuilder )
    {
        var models = modelBuilder.GetEdmModels();
        app.UseMvc( routes => routes.MapVersionedODataRoutes( "odata", null, models  ) );
    }
}

[ApiVersion( "1.0" )] // this attribute isn't required, but it's easier to understand
[ODataRoutePrefix( "People" )]
public class PeopleController : ODataController
{
    // GET ~/people
    // GET ~/people?api-version=1.0
    [ODataRoute]
    public IActionResult Get() => Ok( new[] { new Person() } );
}

[ApiVersion( "2.0" )]
[ControllerName( "People" )]
[ODataRoutePrefix( "People" )]
public class People2Controller : ODataController
{
    // GET ~/people?api-version=2.0
    [ODataRoute]
    public IActionResult Get() => Ok( new[] { new Person() } );
}
Clone this wiki locally