Reputation: 638
I have an ASP.NET Core (3.1) API that use the aspnet-api-versioning (4.1.1) library for versioning. The project is setup to read the version from the URL and use a default version (1) if no version is specified. The example controller supports two API versions (1 and 2) and has two identical methods, one for each version. Since a default version is supported there are two Route attributes on the controller, one without the version and one with.
When generating the OpenAPI documentation for the API, using the Swashbuckle.AspNetCore (5.6.3) library, both the document for API version 1 and 2 will include the non-versioned route; "/Customer/{externalCustomerId}". The problem to solve is, how to configure the Swagger generation to only include the non-versioned routes in the documentation for the default version? Given the code below, the documentation for version 1 should be:
and the documentation for version 2 should be:
Startup:
public class Startup
{
... // Removed for brevity. Method below called from ConfigureServices(...).
private static void ConfigureApiVersioning(IServiceCollection services)
{
services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'V";
setup.SubstituteApiVersionInUrl = true;
});
services.AddApiVersioning(setup =>
{
setup.AssumeDefaultVersionWhenUnspecified = true;
setup.DefaultApiVersion = new ApiVersion(majorVersion: 1, minorVersion: 0);
setup.ReportApiVersions = true;
setup.ApiVersionReader = new UrlSegmentApiVersionReader();
});
}
}
Controller:
[Route("Customer")]
[Route("v{version:apiVersion}/Customer")]
[ApiVersion("1", Deprecated = true)]
[ApiVersion("2")]
[ApiController]
public class CustomerController : ControllerBase
{
[HttpGet("{externalCustomerId}")]
[MapToApiVersion("1")]
public string Get()
{
return "Customer Api v1 responded with 200 ok";
}
[HttpGet("{externalCustomerId}")]
[MapToApiVersion("2")]
public string GetV2()
{
return "Customer Api v2 responded with 200 ok";
}
}
Can (should) it be solved using SwaggerGenOptions.DocInclusionPredicate()
somehow? I gave it a go, but could not figure out a way to get the default API version from the ApiVersion
of the predicate.
One option may be to inherit from the DefaultApiVersionDescriptionProvider
(or implement IApiVersionDescriptionProvider
) to get access to the Options property, which would allow us to get the default API version and use a predicate with a closure in Startup for SwaggerGenOptions.DocInclusionPredicate()
, but is that a good approach to take? What other options exist?
Upvotes: 0
Views: 1918
Reputation: 4418
There are several possibilities:
DocInclusionPredicate
The first one is probably the simplest. Since all properly versioned routes have the route parameter in it, you'd just exclude any that contain it. Something like:
c.DocInclusionPredicate((d, api) => !api.RelativePath.Contains("v{version:apiVersion}"))
You'll need to remove/disable options.SubstituteApiVersionInUrl
; you're not using it anyway.
You should think carefully about what your API documentation is conveying; it's misleading. The OpenAPI/Swagger document will show the correct routes for
2.0
; however, when a client requests it, they will get1.0
. This happens because you've allowed no version to be specified and you assume1.0
. You could use an alternate IApiVersionSelector such as CurrentImplementationApiVersionSelector, but that would merely invert the problem. The purpose of versioning is so that a client can explicitly ask for the version they want.
Upvotes: 0