Explaining ASP.NET Web API Grouping and Versioning in Swagger
Step 1: Understanding the Basics
Before delving into ASP.NET Web API grouping and versioning in Swagger (also known as OpenAPI), it's important to understand the fundamentals of these concepts.
- ASP.NET Web API: This is a framework for building HTTP services that can be consumed by a wide range of clients, including browsers and mobile devices.
- Swagger (OpenAPI): Swagger is a toolchain used to design, build, document, and use RESTful web services. It includes a specification (OpenAPI Specification) and tools to build a service that conforms to that specification.
- Versioning: It's a strategy to handle changes in API behavior without disrupting existing clients. This can be done through URI paths, query strings, request headers, or response headers.
- Grouping: It involves organizing related operations (endpoints) within an API into logical groups for better readability and maintainability.
Swagger integrates seamlessly with ASP.NET Web API to generate and visualize API documentation. By using grouping and versioning in Swagger, you can create well-organized and clear API documentation that reflects changes and improvements over time.
Step 2: Setting Up the Environment
Before you implement grouping and versioning, make sure your project is set up properly. Install necessary NuGet packages for ASP.NET Core and Swagger.
dotnet add package Swashbuckle.AspNetCore
Add Swagger services and middleware in the Startup.cs
or Program.cs
file, depending on your ASP.NET Core version:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.EnableAnnotations(); // Use XML comments for descriptions
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// Add versioning here
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API v1");
// Add versioned endpoints here
});
}
Step 3: Implementing Versioning in ASP.NET Web API
Versioning is essential for evolving APIs. There are several ways to version an API in ASP.NET Core, but one of the most common methods is URI path versioning.
- Add Versioning Services:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerDoc(description.GroupName, new OpenApiInfo()
{
Title = "Sample API",
Version = description.GroupName,
Description = "A sample API versioned with ASP.NET Core"
});
}
c.EnableAnnotations();
});
}
- Annotate Controllers with Version: Use the
[ApiVersion]
attribute to specify the version of the API for each controller.
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new string[] { "value1", "value2" });
}
}
- Configure Swagger to Display Multiple Versions:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
Step 4: Implementing Grouping in ASP.NET Web API
Grouping helps to organize endpoints logically within the API, making it easier to understand and navigate. You can group endpoints by using tags, areas, or custom attributes.
- Using Tags: Use the
[ApiExplorerSettings]
attribute or[SwaggerTag]
attribute to add a tag to the controller. This tag will be used by Swagger to group related endpoints.
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[ApiExplorerSettings(GroupName = "v1")]
public class ValuesController : ControllerBase
{
[HttpGet]
[SwaggerTag("Values Endpoints")]
public IActionResult Get()
{
return Ok(new string[] { "value1", "value2" });
}
}
// Another controller in v2
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[ApiExplorerSettings(GroupName = "v2")]
public class ValuesController : ControllerBase
{
[HttpGet]
[SwaggerTag("Values Endpoints v2")]
public IActionResult Get()
{
return Ok(new string[] { "value3", "value4" });
}
}
- Configure Swagger to Use Tags: In the
services.AddSwaggerGen()
configuration, use thec.DocInclusionPredicate()
method to filter documents based on the API version and tag.
services.AddSwaggerGen(c =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerDoc(description.GroupName, new OpenApiInfo()
{
Title = $"Sample API {description.GroupName}",
Version = description.GroupName,
Description = "A sample API versioned with ASP.NET Core"
});
}
c.TagActionsBy(api => new List<string> { api.GroupName });
c.DocInclusionPredicate((version, desc) =>
{
if (!desc.TryParseApiVersion(out var apiVersion))
{
return false;
}
if (description.GroupName == desc.GroupName)
{
return true;
}
return false;
});
c.EnableAnnotations();
});
Step 5: Enhancing Documentation with XML Comments
Including XML comments in your controllers and models enriches the Swagger documentation. First, enable XML documentation output in your project file:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
Then, modify AddSwaggerGen
to include XML comments:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
Add XML comments to your controllers and actions:
/// <summary>
/// Values Controller
/// </summary>
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
/// <summary>
/// Gets a list of values
/// </summary>
/// <returns>List of string values</returns>
[HttpGet]
public IActionResult Get()
{
return Ok(new string[] { "value1", "value2" });
}
}
Step 6: Testing and Deploying
After implementing versioning and grouping, test the API endpoints through Swagger UI to ensure everything is working as expected. Make sure to test across different versions to verify backward compatibility.
Deploy the application to a production server and monitor the API usage to ensure that versioning and grouping have provided value in maintaining and scaling your API.
Conclusion
Grouping and versioning your ASP.NET Web API in Swagger enhances the maintainability, scalability, and usability of your API. By organizing endpoints logically and managing changes through versioning, you can provide a robust API that meets the needs of your evolving project. Using tools like Swagger alongside best practices in API design ensures that your API remains well-documented and accessible to all consumers.