Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

URL Path Versioning

An alternate, but common, method of API versioning is to use a URL path segment. This approach does not allow implicitly matching the initial, default API version of a service; therefore, all API versions must be explicitly declared. In addition, the API version value specified for the URL segment must still conform to the version format. The v prefix is not part of the API version, but may be included in route templates if you so desire.

Important

It is not possible to have a default API version for a URL path segment. This means that setting ApiVersioningOptions.AssumedDefaultVersionWhenUnspecified is unlikely to have any affect when you use this method of versioning. For more information and possible solutions to address this scenario, refer to the known limitations.

Web API

public static class WebApiConfig
{
    public static void Configuration( HttpConfiguration configuration )
    {
        var constraintResolver = new DefaultInlineConstraintResolver()
        {
            ConstraintMap =
            {
                ["apiVersion"] = typeof( ApiVersionRouteConstraint )
            }
        };
        configuration.MapHttpAttributeRoutes( constraintResolver );
        configuration.AddApiVersioning();
    }
}
[ApiVersion( 1.0 )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorldController : ApiController
{
    public string Get() => "Hello world!";
}

[ApiVersion( 2.0 )]
[ApiVersion( 3.0 )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : ApiController
{
    public string Get() => "Hello world v2!";

    [MapToApiVersion( 3.0 )]
    public string GetV3() => "Hello world v3!";
}

OData

Since the OData implementation uses convention-based routes under the hood, the ApiVersionRouteConstraint is automatically added to all versioned OData routes when needed. The name of the constraint used in prefixes of OData routes must be apiVersion and cannot be changed.

public static class WebApiConfig
{
    public static void Configuration( HttpConfiguration configuration )
    {
        var modelBuilder = new VersionedODataModelBuilder( configuration )
        {
            ModelConfigurations =
            {
                new PersonModelConfiguration()
            }
        };

        configuration.AddApiVersioning();
        configuration.MapVersionedODataRoutes( "odata-bypath", "api/v{apiVersion}", modelBuilder );
    }
}
[ApiVersion( 1.0 )]
[ODataRoutePrefix( "People" )]
public class PeopleController : ODataController
{
    [EnableQuery]
    [ODataRoute]
    public IQueryable<Person> Get() => new[]{ new Person() }.AsQueryable();
}

[ApiVersion( 2.0 )]
[ApiVersion( 3.0 )]
[ControllerName( "People" )]
[ODataRoutePrefix( "People" )]
public class People2Controller : ODataController
{
    [EnableQuery]
    [ODataRoute]
    public IQueryable<Person> Get() => new[]{ new Person() }.AsQueryable();

    [EnableQuery]
    [ODataRoute, MapToApiVersion( 3.0 )]
    public IQueryable<Person> GetV3() => new[]{ new Person() }.AsQueryable();
}

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

Request URLMatched ControllerMatched Action
/api/v1/helloworldHelloWorldControllerGet
/api/v2/helloworldHelloWorld2ControllerGet
/api/v3/helloworldHelloWorld2ControllerGetV3
/api/v1/PeoplePeopleControllerGet
/api/v2/PeoplePeople2ControllerGet
/api/v3/PeoplePeople2ControllerGetV3