-
Couldn't load subscription status.
- Fork 716
API versioning with api-supported-versions header #951
-
I'm curious if I'm doing something wrong with versioning my API.
Currently I've set up this:
services.AddApiVersioning(opt => { opt.AssumeDefaultVersionWhenUnspecified = false; opt.DefaultApiVersion = new ApiVersion(1, 0); opt.ReportApiVersions = true; opt.ApiVersionReader = new UrlSegmentApiVersionReader(); })
With these endpoints:
[ApiController] [Route("/v{version:apiVersion}/users")] [ApiVersion("1.0")] [Authorize] public class UserController : ControllerBase { [HttpGet] [Route("{publicKey}")] public async Task<IActionResult> FindUser(string publicKey) { ... return Ok(result); } [HttpPut] [Route("{userIdValue}")] [Obsolete("Please use the endpoint in V2.")] public async Task<IActionResult> UpdateUser(string userIdValue, UpdateUserRequestDto request) { ... return Ok(result); } [HttpPut] [Route("{userIdValue}")] [ApiVersion("2.0")] public async Task<IActionResult> UpdateUserV2(string userIdValue, UpdateUserRequestV2Dto request) { ... return Ok(result); } }
So now I've got these endpoints showing up correctly in Swagger:
GET -> /v1/user/{publicKey}
PUT -> /v1/user (deprecated)
PUT -> /v2/user
Only when I call the endpoint to get the user, which only has a v1, I get the response api-supported-versions: 1.0, 2.0 which should not happen right? Should it not only show 1.0 here?
Versioning the entire api makes no sense to me but versioning endpoint does. Otherwise with every breaking change the entire api endpoint gets upped 1 version. Even if those endpoints didn't change. Then I also need to make a lot of controller forwards to the legacy controller. Or am I missing something here.
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment
-
There is a conflation between the meaning of API with respect to an endpoint. While it's true that a single endpoint can be an API, it's not all that practical. Most APIs are a collection of endpoints. For example, GET /order/{id} and POST /order might be called the Orders API.
Collation is performed by the logical name of the API; not the route template. Route templates cannot safely be collated. For example, order/{id} and order/{id:int} are semantically equivalent, but they aren't the same. API Versioning makes no attempt to understand route templates. Furthermore, should order/{id}/items be part of the Orders API or some other API? Only the author knows that. When you version using the controllers, the name of the controller is the logically name of the API and how versions are collated; in your case, User. Collation only occurs by name. In addition to not considering route template, it doesn't consider HTTP method either.
An API and its versions make up a lot more than just an endpoint. An API version cannot not define the entire policy associated with an API. OpenAPI and (the new) sunset policies provide additional context for client that you just can't get from a list of supported and deprecated versions. In this scenario, if GET is requested for 2.0, then 405 is returned. This might seems a mismatch, but the server is communicating the available versions of an API, not just a single endpoint. If the client was bound to 1.0, how would they ever know there was a 2.0 from a GET request as it is no longer supported?
I hope that helps and clarifies a few things.
Beta Was this translation helpful? Give feedback.