PluginBench
Skill
Pass
Audit score 90

api-versioning

codewithmukesh/dotnet-claude-kit

API versioning strategies for ASP.NET Core using Asp.Versioning library with URL, header, and query string approaches.

What is api-versioning?

Implement API versioning in ASP.NET Core to manage breaking changes and maintain backward compatibility. Use this skill when adding versioning to a new API, evolving an existing API with breaking changes, or when the user mentions version management, deprecation, or backward compatibility.

  • Set up Asp.Versioning library with URL segment, header, or query string strategies
  • Organize endpoints into version-specific groups with separate response shapes
  • Mark API versions as deprecated and communicate sunset dates to clients
  • Integrate versioning with OpenAPI/Swagger documentation
  • Map version-specific endpoint handlers that transform responses per version

How to install api-versioning

npx skills add https://github.com/codewithmukesh/dotnet-claude-kit --skill api-versioning
Prerequisites
  • ASP.NET Core 6.0 or later
  • Asp.Versioning NuGet package installed
  • Basic understanding of ASP.NET Core routing and minimal APIs
Claude Code
Cursor
Windsurf
Cline

How to use api-versioning

  1. 1.Install Asp.Versioning via NuGet and configure it in Program.cs with an ApiVersionReader strategy
  2. 2.Choose a versioning strategy: URL segment (recommended for public APIs), header (for internal APIs), or query string
  3. 3.Create separate endpoint handler classes for each version (e.g., OrderEndpointsV1, OrderEndpointsV2)
  4. 4.Map endpoint groups using MapGroup with version sets and route to version-specific handlers
  5. 5.Mark versions as deprecated using HasDeprecatedApiVersion() when releasing a new version
  6. 6.Test that clients receive correct response shapes and deprecation headers

Use cases

Good for
  • Adding versioning to a new public API from day one to avoid painful refactoring later
  • Releasing a breaking change by creating a new version while keeping the old version available
  • Deprecating an old API version with a timeline and migration guidance for clients
  • Supporting multiple response shapes for the same endpoint across different versions
  • Organizing internal service-to-service APIs using header-based versioning for cleaner URLs
Who it's for
  • ASP.NET Core API developers managing public or internal APIs
  • Backend engineers evolving APIs with breaking changes
  • Teams needing to maintain multiple API versions simultaneously
  • Architects designing API deprecation strategies

api-versioning FAQ

Should I version individual endpoints or the entire API?

Version the entire API group. All endpoints in a version should share the same version number for consistency. Versioning individual endpoints creates confusion and maintenance overhead.

What's the best versioning strategy for a public REST API?

URL segment versioning (/api/v1/orders) is recommended because it's discoverable, cache-friendly, and follows REST conventions. Header versioning is better for internal service-to-service APIs.

How do I handle breaking changes?

Create a new version with the breaking change and keep the old version running. Mark the old version as deprecated with a sunset date, then provide clear migration documentation for clients.

Can I add new optional fields without creating a new version?

Yes. Adding optional fields is backward compatible and does not require a new version. Only breaking changes—removing fields, changing types, or altering behavior—require a new version.

How do I communicate version deprecation to clients?

Use the api-deprecated-versions response header (set automatically by Asp.Versioning) and document the sunset date and migration path in your API documentation.

Full instructions (SKILL.md)

Source of truth, from codewithmukesh/dotnet-claude-kit.


name: api-versioning description: > API versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment, header, and query string strategies, version deprecation, and OpenAPI integration. Load this skill when adding versioning to an API, evolving an API with breaking changes, or when the user mentions "API version", "versioning", "v1/v2", "Asp.Versioning", "deprecation", "breaking change", or "backward compatibility".

API Versioning

Core Principles

  1. Version from day one — Adding versioning later is painful. Start with a version in the URL even if you only have v1.
  2. URL segment versioning is the default — /api/v1/orders is the most discoverable and cache-friendly strategy.
  3. Never break existing versions — Add a new version for breaking changes. Deprecate the old version with a timeline.
  4. Version the API, not individual endpoints — All endpoints in a version group share the same version number.

Patterns

Setup with Asp.Versioning

// Program.cs
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
    options.ApiVersionReader = new UrlSegmentApiVersionReader();
})
.AddApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

URL Segment Versioning (Recommended)

var v1 = app.NewApiVersionSet()
    .HasApiVersion(new ApiVersion(1, 0))
    .Build();

var v2 = app.NewApiVersionSet()
    .HasApiVersion(new ApiVersion(2, 0))
    .Build();

app.MapGroup("/api/v{version:apiVersion}/orders")
    .WithApiVersionSet(v1)
    .WithTags("Orders")
    .MapOrderEndpointsV1();

app.MapGroup("/api/v{version:apiVersion}/orders")
    .WithApiVersionSet(v2)
    .WithTags("Orders")
    .MapOrderEndpointsV2();

Header Versioning (Alternative)

options.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version");

// Client sends: X-Api-Version: 2.0

Deprecating a Version

var v1 = app.NewApiVersionSet()
    .HasDeprecatedApiVersion(new ApiVersion(1, 0))
    .HasApiVersion(new ApiVersion(2, 0))
    .Build();

// Response headers will include: api-deprecated-versions: 1.0

Version-Specific Endpoint Groups

public static class OrderEndpointsV1
{
    public static RouteGroupBuilder MapOrderEndpointsV1(this RouteGroupBuilder group)
    {
        group.MapGet("/{id:guid}", GetOrderV1);
        group.MapPost("/", CreateOrderV1);
        return group;
    }

    private static async Task<Results<Ok<OrderResponseV1>, NotFound>> GetOrderV1(
        Guid id, ISender sender, CancellationToken ct)
    {
        // V1 response shape
        var result = await sender.Send(new GetOrder.Query(id), ct);
        return result.IsSuccess
            ? TypedResults.Ok(result.Value.ToV1())
            : TypedResults.NotFound();
    }
}

public static class OrderEndpointsV2
{
    public static RouteGroupBuilder MapOrderEndpointsV2(this RouteGroupBuilder group)
    {
        group.MapGet("/{id:guid}", GetOrderV2);
        group.MapPost("/", CreateOrderV2);
        return group;
    }

    private static async Task<Results<Ok<OrderResponseV2>, NotFound>> GetOrderV2(
        Guid id, ISender sender, CancellationToken ct)
    {
        // V2 response shape — includes new fields
        var result = await sender.Send(new GetOrder.Query(id), ct);
        return result.IsSuccess
            ? TypedResults.Ok(result.Value.ToV2())
            : TypedResults.NotFound();
    }
}

Anti-patterns

Don't Version Individual Endpoints

// BAD — inconsistent versioning within a group
app.MapGet("/api/v1/orders", ListOrdersV1);
app.MapGet("/api/v2/orders/{id}", GetOrderV2); // V2 only for this endpoint?

// GOOD — version the entire group
app.MapGroup("/api/v1/orders").MapOrderEndpointsV1();
app.MapGroup("/api/v2/orders").MapOrderEndpointsV2();

Don't Use Query String Versioning as Default

// BAD for REST APIs — version hidden in query string, not cache-friendly
GET /api/orders?api-version=2.0

// GOOD — version in URL, discoverable and cacheable
GET /api/v2/orders

Decision Guide

ScenarioRecommendation
New public APIURL segment versioning from day one
Internal API between servicesHeader versioning (cleaner URLs)
Breaking response shape changeNew version
Adding new optional fieldsSame version (backwards compatible)
Deprecating a versionMark deprecated, set sunset date, document migration path