Recently, I worked with an Asp.Net Core API project. I have added API specification with swagger /
Update on December 27, 2019 : I have added another post to migrate the project to ASP.Net core 3.1
Table of Contents
Overview
As we learn and explore we change our systems to cope with changes. Embracing changes and being flexible is a couple of imperative requirements for any business. API versioning allows your service to grow with new changes gradually so that your client can join you at their pace. However, we have a legacy API behind an AWS API Gateway which we want to rewrite. So, we chose the URL path segment versioning. Depending on the URL, API gateway will send the request to version-1 or new API. However, we also keep in mind that new API may support more than one version. To learn how to configure an AWS API Gateway you can check my post Build an API Gateway with Lambda Function in
OpenAPI Specification
As Swagger.io define about OAS
The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.
API Version with OpenAPI Specification – Swagger
Create A new Asp.net Core web application project and select API. Next up we need to add following packages
Nuget Packages
Just add following two packages and that’s all the packages you need for version and API documentation. One for API Versioning and another for swagger
- Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
- Swashbuckle.AspNetCore
Microsoft.AspNetCore.Mvc.Versionning.ApiExplorer (3.2.0) depends on Microsoft.AspNetCore.Mvc.ApiExplorer (2.2.0) and Microsoft.AspNetCore.Mvc.Versioning (3.1.2). You may find the implementation of these packages here
Swashbuckle.AspNetCore depends on three packages and they are
- Swashbuckle.AspNetCore.Swagger (4.0.1)
- Swashbuckle.AspNetCore.SwaggerGen (4.0.1)
- Swashbuckle.AspNetCore.SwaggerUI (4.0.1)
XML Documentation
You need to enable the XML documentation for the
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\RestAPI.Example.xml</DocumentationFile>
<LangVersion>latest</LangVersion>
</PropertyGroup>
Configure XML Documentation in a way so that XML file creates for all builds. You can also do this from the project property page, but careful about the configuration and target framework!!
Startup.cs
Configure Services
The following code will add API versioning and an API explorer (that is API version aware) services in Startup.ConfigureService method
services.AddVersionedApiExplorer().AddApiVersioning();
And also we need to add swagger gen service.
services.AddSwaggerGen();
To configure swagger generate service according to your requirements you may inject custom implementations of
public sealed class ConfigureSwaggerGenOptions : IConfigureOptions<SwaggerGenOptions>{
// ctor....................
// Configure(SwaggerGenOptions options)
private void AddSwaggerDocumentForEachDiscoveredApiVersion(SwaggerGenOptions options) {
foreach (var description in provider.ApiVersionDescriptions){
settings.Info.Version = description.ApiVersion.ToString();
if (description.IsDeprecated) settings.Info.Description += " - DEPRECATED";
options.SwaggerDoc(description.GroupName, settings.Info);
}
}
}
Add version group as the document name. Swagger info is reading from the configuration, and also depreciation is added to the description if the version is marked as Depreciated.
Find the full implementation of ConfigureSwaggerGenOptions here
I have added following three services to customise swagger options
services
.AddTransient<IConfigureOptions<SwaggerOptions>, ConfigureSwaggerOptions>()
.AddTransient<IConfigureOptions<SwaggerUIOptions>, ConfigureSwaggerUiOptions>()
.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerGenOptions>();
Configure
I have used an extension method to add
app.UseSwagger();
app.UseSwaggerUI();
To configure Swagger and SwaggerUI I have added two transient services ConfigureSwaggerOptions and ConfigureSwaggerUiOptions. You can directly use it on startup.cs, but I would like to keep separate from this class. I find this approach neat and clean. I have added a sample below
public sealed class ConfigureSwaggerUiOptions : IConfigureOptions<SwaggerUIOptions>{ private readonly IApiVersionDescriptionProvider provider;
private readonly SwaggerSettings settings; public ConfigureSwaggerUiOptions(IApiVersionDescriptionProvider versionDescriptionProvider, IOptions settings) { this.provider = versionDescriptionProvider; this.settings = settings?.Value ?? new SwaggerSettings(); } public void Configure(SwaggerUIOptions options) { provider .ApiVersionDescriptions .ToList() .ForEach(description => { options.SwaggerEndpoint($"/{settings.RoutePrefixWithSlash}{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant()); options.RoutePrefix = settings.RoutePrefix; }); } }
Here, I am using IApiVersionDescriptionProvider to add the route prefix and document name for each version. If you do not want to create a separate class, you may use the following code to add swagger middleware
app.UseSwagger(options =>
options.RouteTemplate = settings.RoutePrefixWithSlash + "{documentName}/swagger.json"
);
UI
You can use SwaggerUI or ReDoc to show the API specifications to API users. If you download the asp.net core sample and run it locally, you will see the version dropdown on the right, and selecting version filters the list of API calls.
Conclusion
Finally, here is an example implementation I have added to