Giter Site home page Giter Site logo

Comments (2)

commonsensesoftware avatar commonsensesoftware commented on May 16, 2024

There are a couple of different issues going on here so let me try to break up the response into pieces.

URL Path Versioning

When you version your API in the URL path, you can't logically have a default version. The API version is instrinsically part of the path. In your example, you have the route template api/{version:apiVersion}/Uri. If an API version is not specified using this method, the URL becomes api//Uri.

Most service authors that use URL path versioning prefix the API version segment value with the letter 'v'. This would make the route template api/v{version:apiVersion}/Uri. Now, if an API version isn't specified, the path will become api/v/Uri. I think it's pretty obvious that this won't exist.

The method in which the requested API version is internally set is - ever so slightly - different that any other method. All other methods go through the IApiVersionReader to extract the API version from the incoming request message. Trying to understand and parse the URL path in the same manner would be difficult and brittle. Since ASP.NET already provides a structured way to parse route templates, URL path versioning uses a route constraint instead. This allows you to craft your URLs however you want and just indicate which segment the API version should be extracted from.

You can use the route template as you defined it, but there is no way to assume a default because there are no matching candidates.

Default Version Selection

It may not be intrinsically obvious, but the DefaultApiVersion and ApiVersionSelector options are somewhat mutually exclusive. The purpose of the DefaultApiVersion is to simply define an assumed version without hard-coding the value for all fallback cases because every service always has some logical version number, even if it's not formally defined. The IApiVersionSelector is the extension point to select the appropriate API version given a request and the discovered API version model. The infrastructure does all the hard work of collecting the available API versions and you select the best one.

In your case, you elected to use the CurrentImplementationApiVersionSelector and have the following API versions defined:

  • 1.0 (implemented, but deprecated)
  • 2.0
  • 3.0

This selector will always choose 3.0 from these choices. The only time it would ever use the default configured API version of 2.0 is if there were no candidate API versions to select from. For example, if your versions were all pre-release:

  • 1.0-alpha
  • 2.0-beta
  • 3.0-rc

Any version with a status is not considered implemented. Additionally, deprecated does not mean not implemented.

If your intent was to have all clients that don't request a version start on 2.0, then you can just set the DefaultApiVersion. The default value for the ApiVersionSelector is an instance of the DefaultApiVersionSelector, which just always uses the value of the configured DefaultApiVersion.

Faking a Default API Version with URL Paths

There is one way that you can give the impression of an implicitly-version URL path. To enable this, you need to make multiple routes per controller. API versioning stays out of the way of routing and only gets involved with resolving the appropriate controllers and actions.

For example, if your controllers were updated with additional routes:

[ApiVersion( "1.0", Deprecated = true )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class UriController : ApiController { /* ommitted */ }

[ApiVersion( "2.0" )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class Uri2Controller : ApiController { /* ommitted */ }

[ApiVersion( "3.0" )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class Uri3Controller : ApiController { /* ommitted */ }

Your controllers will be resolved using the following URLs:

URL Version Controller
api/uri 3.0 Uri3Controller
api/1/uri 1.0 UriController
api/2/uri 2.0 Uri2Controller
api/3/uri 3.0 Uri3Controller
api/uri?api-version=1.0 1.0 UriController
api/uri?api-version=2.0 2.0 Uri2Controller
api/uri?api-version=3.0 3.0 Uri3Controller

The last 3 entries are there because the default configuration uses an IApiVersionReader that extracts the API version from the api-version query string parameter. If you want to remove this behavior, you can implement a reader that always returns null.

public class IgnoreApiVersionReader : IApiVersionReader
{
    public string Read( HttpRequestMessage request ) => null;
}

You may have noticed that the example used the names UriController, Uri2Controller, and Uri3Controller. In setting up an example that would simulate your scenario, I found an edge case bug. I'll create a new issue for this bug and correlate it back to this thread. For now, using different type names will make this setup work.

I hope that helps.

from aspnet-api-versioning.

nomttr avatar nomttr commented on May 16, 2024

You well explained the problem with URL path versioning and DefaultApiVersion. Multiple routes on controller makes it bit confusing so i'm considering to choose e.g Custom Header versioning as this one fits better my scenario. Anyway thanks a lot for answer and solution. Cheers!

from aspnet-api-versioning.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.