Previously…
… I wrote about how to generate Swagger/OAS 3 with versioning in an ASP.Net Core API.
But why stop there, lets do some touch-ups on that code.
First of all
This will build on the code from the previous blog-post.
I will include code for the accept header scenario, removing the parts needed for the separate header scenario. I will include all the classes that are needed for this.
Asumptions and nugets
Are the same as the previous blog post. Nothing has happened in this area since i wrote the last post.
Lets go to the code…
The steps needed are:
- Add the classes needed to config the API-Version and Swagger.
- Include method calls in the Startup class.
– ConfigureSwaggerOptions and the ISwaggerVersionInfoProvider
This interface and class lets us configure the options after the service has been resolved.
public interface ISwaggerVersionInfoProvider
{
OpenApiInfo GetVersionInfo(ApiVersionDescription apiDescription);
}
/// <summary>
/// Configures the Swagger generation options.
/// </summary>
/// <remarks>This allows API versioning to define a Swagger document per API version after the
/// <see cref="IApiVersionDescriptionProvider"/> service has been resolved from the service container.</remarks>
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
/// </summary>
/// <param name="provider">The <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;
/// <inheritdoc />
public void Configure(SwaggerGenOptions options)
{
// 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, CreateInfoForApiVersion(description));
}
// Add a custom operation filter which sets default values
//options.OperationFilter<SwaggerDefaultValues>();
// Integrate xml comments, add this when we have come that far.
//options.IncludeXmlComments(XmlCommentsFilePath);
// Describe all enums as strings instead of integers.
//options.DescribeAllEnumsAsStrings();
}
// <summary>
/// Creates an API-Version info object and fills it with data.
/// </summary>
/// <param name="description"></param>
/// <returns>Returns an OpenApiInfo object with API-Version info.</returns>
public static OpenApiInfo CreateInfoForApiVersion(this ApiVersionDescription description)
{
var info = new OpenApiInfo()
{
Title = $"Test API {description.ApiVersion}",
Version = description.ApiVersion.ToString(),
Description = "This is the swagger base info for API.",
Contact = new OpenApiContact() { Name = "Contact Name", Email = "some@email.com" },
//TermsOfService = "UnComment and put the URI here to the terms of service.",
License = new OpenApiLicense() { Name = "MIT", Url = new Uri("https://opensource.org/licenses/MIT") }
};
if (description.IsDeprecated)
{
info.Description += " This API version has been deprecated.";
}
return info;
}
}
– SwaggerGenerationSetupExtensionMethods
This one we know from the last post but there are some minor changes to it.
We have removed the CreateInfoForApiVersions method as it has been moved to the ConfigureSwaggerOptions class. You could probably remove the AddSwaggerGeneration and do all the configuration from the ConfigureSwaggerOptions class, but I am keeping it here for the time being.
/// <summary>
/// Extension methods for adding and configuring Swashbuckle/Swagger (OAS3) generation.
/// https://github.com/Microsoft/aspnet-api-versioning/wiki/Swashbuckle-Integration
/// </summary>
public static class SwaggerGenerationSetupExtensionMethods
{
/// <summary>
/// Adds and configures Swashbuckle/Swagger (OAS3) generation.
/// </summary>
/// <param name="services"></param>
public static void AddSwaggerGeneration(this IServiceCollection services)
{
services.AddSwaggerGen(options =>
{
// Integrate xml comments, add this when we have come that far.
//options.IncludeXmlComments(XmlCommentsFilePath);
// Describe all enums as strings instead of integers.
//options.DescribeAllEnumsAsStrings();
});
}
/// <summary>
/// Adds SwaggerUI and adds a API-Version for each discovered endpoint.
/// </summary>
/// <param name="app"></param>
/// <param name="provider"></param>
public static void UseSwaggerUIAndAddApiVersionEndPointBuilder(IApplicationBuilder app, IApiVersionDescriptionProvider provider)
{
app.UseSwaggerUI(c =>
{
// Build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
}
– ApiVersionSetupExtensionMethods
This one is here with minor unimportant changes since last post.
public static class ApiVersionSetupExtensionMethods
{
/// <summary>
/// Adds API-Versioning with settings and API-Explorer with settings.
/// </summary>
/// <param name="services">The services collection to add to.</param>
public static void AddApiVersioningAndExplorer(this IServiceCollection services)
{
// Add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
// Note: the specified format code will format the version as "'v'major[.minor][-status]"
services.AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
});
services.AddApiVersioning(
options =>
{
options.ReportApiVersions = true;
// Use this if you would like to use the MediaType version header.
// Eg: Header 'Accept: application/json; v=1.0'
options.ApiVersionReader = new MediaTypeApiVersionReader();
// This is set to true so that we can set what version to select (default version)
// when no version has been selected.
options.AssumeDefaultVersionWhenUnspecified = true;
// And this is where we set how to select the default version.
options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);
});
}
}
– Startup
The Startup class has one line changed since the last blog-post. The line where we include the new interface and class.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest);
services.AddApiVersioningAndExplorer();
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGeneration();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseSwagger();
app.UseSwaggerUIAndAddApiVersionEndPointBuilder(provider);
app.UseMvc();
}
}
Rounding off
This has been a touch-up post only. With very little info.
I will undoubtedly get back to this subject again…
You must be logged in to post a comment.