Hopefully somebody has tried something similar with a versioned API in MVC 6 and Swagger to display documentation about the different versions.
I am using the recommended API versioning in MVC 6 as per this ASP.NET 5 repository. The only change I have made is the GetVersion method to read the api version from the request's custom http header:
//in VersionRangeValidator.cs
public static string GetVersion(HttpRequest request)
{
//return request.Query["version"];
if (!string.IsNullOrWhiteSpace(request.Headers[Constants.CommonRoutingDefinitions.ApiVersionSegmentName]))
{
return request.Headers[Constants.CommonRoutingDefinitions.ApiVersionSegmentName];
}
return Constants.CommonRoutingDefinitions.CurrentApiVersion;
}
and I have a controller like this:
[Route("api/[controller]")]
[Produces(Constants.MediaTypeNames.ApplicationJson)]
public class TagsController : Controller
{
private readonly ITagService _tagService;
public TagsController(ITagService tagService)
{
_tagService = tagService;
}
/// <summary>
/// Version 1 by default
/// </summary>
/// <returns>All the tags</returns>
[HttpGet]
[Produces(typeof(IEnumerable<Tag>))]
public IEnumerable<Tag> GetTags()
{
IEnumerable<Tag> tags = _tagService.GetTags();
return tags;
}
/// <summary>
/// Version 2
/// </summary>
/// <returns>All the tags V2</returns>
[VersionGet("", versionRange: "[2]")]
public IEnumerable<Tag> GetTagsV2()
{
IList<Tag> tags = new List<Tag>
{
new Tag { Id = 1, Links = Enumerable.Empty<Link>().ToList(), Name = "Tag version 2" }
};
return tags;
}
}
The versioning happens with a custom http header so that
GET /api/tags
Content-Type: application/json
will hit the GetTags() action by default as no header has been specified and the
GET /api/tags
api-version: 2
Content-Type: application/json
will hit the GetTagsV2() action.
I have added Swagger UI and Swagger GEN libraries following steps at this blog so in my project.json
I have de following dependencies:
"Swashbuckle.SwaggerGen": "6.0.0-rc1-final",
"Swashbuckle.SwaggerUi": "6.0.0-rc1-final"
Then in my Startup.cs I add Swagger to the pipeline with
//inside Configure(IApplicationBuilder app)
app.UseSwaggerGen();
app.UseSwaggerUi();
and I configure Swagger as follows:
private void ConfigureSwagger(IServiceCollection services)
{
services.AddSwaggerGen();
services.ConfigureSwaggerDocument(options =>
{
options.MultipleApiVersions(new Swashbuckle.SwaggerGen.Info[]
{
new Swashbuckle.SwaggerGen.Info
{
Version = "v1",
Title = "MyApp API",
Description = "A RESTful API"
},
new Swashbuckle.SwaggerGen.Info
{
Version = "v2",
Title = "MyApp API (v2)",
Description = "A RESTful API"
}
}, (description, version) => {
//description is an instance of ApiDescription and
//version is either "v1" or "v2"
//depending on the user choice in swagger UI page
//TODO, how can I know whether the action belongs to v1 or to v2 to return true or false as appropriate?
});
options.OperationFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlActionComments(Configuration["Documentation:SwaggerDocXml"]));
});
services.ConfigureSwaggerSchema(options =>
{
options.DescribeAllEnumsAsStrings = true;
options.ModelFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlTypeComments(Configuration["Documentation:SwaggerDocXml"]));
});
}
The problem is that I don't know how to get from the description (which is an instance of Microsoft.AspNet.Mvc.ApiExplorer.ApiDescription) the necessary information to know whether that given action has to be displayed in Swagger UI or not depending on the specified version. Any tip would be greatly appreciated. It would help to understand how the this ASP.NET 5 repository implementation for versioning works because I still don't understand it well and cannot find a good explanation on how the action constraints work.
PS: This stackoverflow question helped me implement the versioning with MVC 6 but I couldn't find much about how Swagger would integrate with this way of versioning an API.
My first answer to a question here, hope you find it useful. My apologies for the bad formatting of the code snippet but have little time on my hands now.
You were almost there but you didn't add the filter for version in the description. This works in my implementation for the following url format:
"/v1/Sessions" and "/v3/Sessions"
options.MultipleApiVersions(new Info[]{
new Info
{
Version = "v1",
Title = "your_own",
Description = "Defines the API to access... your_own",
TermsOfService = "your_own",
Contact = new Contact()
{
Email = "your_own",
Name = "your_own"
}
},
new Info
{
Version = "v3",
Title = "your_own",
Description =
"Defines the API to .... your_own",
TermsOfService = "your_own",
Contact = new Contact()
{
Email = "your_own",
Name = "your_own"
}
}}, (description, version) => {
//Here we compare if the version is part of the incoming URI, if yes, show it on swagger page.
return description.RelativePath.ToLower().Contains(version.ToLower()); } );
It seems that you have a custom VersionGet
attribute. You can use this to determine the v2 endpoints. The other endpoints may default to v1 (if this is what you want).
Here's a snippet I use. Note that my custom attribute is named ApiVersion2
.
public static bool ResolveVersion(ApiDescription apiDesc, string targetApiVersion)
{
if (targetApiVersion == "v2")
{
ApiVersion2Attribute v2Attr = apiDesc.ActionDescriptor.GetCustomAttributes<ApiVersion2Attribute>().FirstOrDefault();
if (v2Attr != null)
return true;
}
if (targetApiVersion == "v1")
return true;
throw new NotSupportedException();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With