6724
views
✓ Answered

Mastering API Versioning with OpenAPI in .NET 10: A Practical Q&A Guide

Asked 2026-05-03 16:38:09 Category: Programming

API versioning is a critical practice for any long-lived API, allowing you to introduce changes without breaking existing clients. With .NET 10, Microsoft has strengthened OpenAPI support through Microsoft.AspNetCore.OpenApi, and the Asp.Versioning v10 package now seamlessly integrates with it. This Q&A covers everything you need to know—from why versioning matters to implementing it with Minimal APIs and controllers, generating separate OpenAPI documents, and visualizing documentation with SwaggerUI or Scalar. Follow along step by step, and you'll keep both your API evolution and documentation clean.

Why is API versioning important, and what strategies exist?

API versioning ensures backward compatibility as your API evolves. Without it, a single breaking change could disrupt all existing clients. Common strategies include:

Mastering API Versioning with OpenAPI in .NET 10: A Practical Q&A Guide
Source: devblogs.microsoft.com
  • URL Path Versioning – e.g., /api/v1/users
  • Query String Versioning – e.g., /api/users?version=1
  • Header Versioning – e.g., X-API-Version: 1
  • Media Type Versioning – using the Accept header.

Each approach has trade-offs. URL path versioning is the most visible and commonly used. The choice depends on your API's requirements and client expectations. The key is to pick a strategy and apply it consistently, which the Asp.Versioning library makes straightforward in .NET 10.

What changed with OpenAPI and versioning in .NET 10?

Prior to .NET 9, adding OpenAPI documentation for versioned APIs required custom work or third-party libraries. Microsoft.AspNetCore.OpenApi, introduced in .NET 9, provides built-in OpenAPI support but initially lacked tight versioning integration. With .NET 10 and Asp.Versioning v10, Microsoft's package now generates separate OpenAPI documents per version automatically (e.g., /openapi/v1.json, /openapi/v2.json). This eliminates duplicated configuration and manual wires. The library also respects the versioning scheme you choose, so whether you use URL path, header, or query string versioning, your OpenAPI output reflects the correct endpoints and schemas for each version.

How do I implement API versioning in a .NET 10 application with Minimal APIs?

Start by adding the Asp.Versioning.Http and Asp.Versioning.MinimalApi NuGet packages. In Program.cs, configure versioning:

builder.Services.AddApiVersioning(options =>
{
    options.ReportApiVersions = true;
    options.AssumeDefaultVersionWhenUnspecified = true;
}).AddApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

Then, on your Minimal API endpoints, use MapVersionedEndpoint or simply call .HasApiVersion(1.0) on route handlers. For example:

app.MapGet("/api/v{version:apiVersion}/products", (ApiVersion version) =>
{
    return Results.Ok(new { Version = version.ToString() });
}).HasApiVersion(1.0);

This ensures that each endpoint is bound to the specified version. The ApiVersion parameter is automatically injected. You can build multiple version sets by chaining different routes or using version policies.

How does versioning work with controllers in .NET 10?

Controllers follow a similar pattern but use attributes. Install the Asp.Versioning.Mvc.ApiExplorer package (for OpenAPI integration). Decorate your controller with [ApiVersion("1.0")] and optionally [Route("api/v{version:apiVersion}/[controller]")]. For example:

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetProducts(ApiVersion version)
    {
        return Ok(new { Version = version.ToString() });
    }
}

For multiple versions, create separate controllers with different version attributes or use a single controller and let the versioning middleware map the correct action. The SubstituteApiVersionInUrl option, when set to true, automatically replaces {version:apiVersion} in the route with the actual version number for OpenAPI document generation.

Mastering API Versioning with OpenAPI in .NET 10: A Practical Q&A Guide
Source: devblogs.microsoft.com

How do I generate separate OpenAPI documents for each API version?

After setting up versioning as described, add OpenAPI support by calling AddOpenApi() on the service collection. To produce distinct documents per version, configure the OpenApiOptions using the Asp.Versioning.Options pattern:

builder.Services.AddOpenApi("v1", options =>
{
    options.AddDocumentTransformer((document, context, cancellationToken) =>
    {
        document.Info.Version = "1.0";
        return Task.CompletedTask;
    });
});
// Repeat for v2, v3, etc.

Or use a dynamic approach by iterating over the supported API versions from builder.Services.GetRequiredApiVersionSet(). Then, in the pipeline, call app.MapOpenApi() without parameters—the framework will create endpoints like /openapi/v1.json and /openapi/v2.json automatically. This keeps your OpenAPI documentation in sync with your actual versioned routes.

How can I visualize versioned API docs with SwaggerUI or Scalar?

Once you have OpenAPI documents per version, add a UI. For SwaggerUI, use the Swashbuckle.AspNetCore.SwaggerUI package:

app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/openapi/v1.json", "API v1");
    options.SwaggerEndpoint("/openapi/v2.json", "API v2");
});

For Scalar, install Scalar.AspNetCore and add:

app.MapScalarApiReference(options =>
{
    options.WithOpenApiRoutePattern("/openapi/{documentName}.json");
});

Both tools will display version dropdowns, allowing developers to test each version separately. Ensure your AddApiExplorer configuration includes GroupNameFormat = "'v'VVV" so that the version group names match the document names (v1, v2).

How do I maintain versioned APIs as my application evolves?

Plan your versioning strategy early. Deprecate versions gracefully by setting options.ReportApiVersions = true to include sunset headers. Use the [Deprecated] attribute or options.DeprecatedApiVersions to mark endpoints as deprecated. In OpenAPI, you can add custom transformers to set a deprecated flag on each endpoint. For breaking changes, introduce a new version rather than modifying an existing one. Keep your OpenAPI documents updated by regenerating them when you add or remove versioned endpoints. Regularly audit version usage via logging and client feedback. Tools like Automatically generate changelog from OpenAPI diffs can help communicate changes to consumers.