1

I have setup Swagger/Swashbuckle on my WebAPI project. I have followed the guide from Microsoft which covers how to setup Aspnet.WebApi.Versioning with Swagger. My API has multiple versions, so there is a {version} parameter set in the route attributes, like this:

[ApiVersion("2")]
[RoutePrefix("api/{version:apiVersion}/values")]
public class AccountController : ApiController
{
    [Route("UserInfo")]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

My issue is that this shows a {version} attribute in the path shown in the docs, like this:

enter image description here

Instead I want this path attribute to actually have the value in the ApiVersion attribute, so that there can be no confusion for the clients who read the documentation. Ideally, given that the UrlDiscoverySelector is set to v2 the paths above should be:

/api/2/account/userinfo
/api/2/account/externallogin
/api/2/account/manageinfo

My attempts to simply replace the {version} in the RelativePath of the ApiExplorer worked in the UI, but broke the test functionality as {version} was changed to a query parameter instead of a path, which is not how my API is configured.

Is it possible I can amend the values in the ApiExplorer before swagger builds the documentation while still retaining test functionality?

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339

2 Answers2

3

The API Explorer for API versioning now supports the behavior out-of-the-box using:

options.SubstituteApiVersionInUrl = true

This will do the substitution work for you and removes the API version parameter from the action descriptor. You generally don't need to change the default format applied to the substituted value, but you can change it using:

options.SubstitutionFormat = "VVV"; // this is the default
Chris Martinez
  • 3,185
  • 12
  • 28
0

I'm using a Swashbuckle and used a Document filter

public class VersionedOperationsFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach (var apiDescriptionsGroup in context.ApiDescriptionsGroups.Items)
        {
            var version = apiDescriptionsGroup.GroupName;
            foreach (ApiDescription apiDescription in apiDescriptionsGroup.Items)
            {
                apiDescription.RelativePath = apiDescription.RelativePath.Replace("{version}", version);
            }
        }
    }
}

and in ConfigureServices method in Startup.cs add this filter:

services.AddMvc();
        var defaultApiVer = new ApiVersion(1, 0);


        services.AddApiVersioning(option =>
        {
            option.ReportApiVersions = true;
            option.AssumeDefaultVersionWhenUnspecified = true;
            option.DefaultApiVersion = defaultApiVer;
        });

        services.AddMvcCore().AddVersionedApiExplorer(e=>e.DefaultApiVersion = defaultApiVer);

        services.AddSwaggerGen(
            options =>
            {
                var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
                options.DocumentFilter<VersionedOperationsFilter>();

                //// add a swagger document for each discovered API version
                //// note: you might choose to skip or document deprecated API versions differently
                foreach (var description in provider.ApiVersionDescriptions)
                {
                        options.SwaggerDoc(description.GroupName.ToString(),
                            CreateInfoForApiVersion(description));
                }

                //// integrate xml comments
                options.IncludeXmlComments(Path.ChangeExtension(Assembly.GetEntryAssembly().Location, "xml"));

            });

end result in Swagger UI

  • Thanks for your reply, and apologies for the late response as I've only just got around to looking at this again. Your code looks ideal, however the signature you're using for the `IDocumentFilter` doesn't match the version of Seashbuckle I'm using. It instead expects `Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)` - note that I'm working on a WebApi project, not an MVC one, should it make a difference – Rory McCrossan Jun 22 '17 at 16:56
  • The thing is that I'm using Swashbuckle.AspNetCore version so it has a different signature but principle should be the same - like [here](https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Dummy.Core/SwaggerExtensions/AppendVersionToBasePath.cs#L14) – Kirill.S Jun 25 '17 at 14:19