aspnet-api-versioning icon indicating copy to clipboard operation
aspnet-api-versioning copied to clipboard

ASP 9 minimal api (without Swashbuckle) - DefaultApiVersion not documented in openapi json

Open spaasis opened this issue 6 months ago • 1 comments
trafficstars

Is there an existing issue for this?

  • [x] I have searched the existing issues

Describe the bug

Hi!

With the default asp net minimal template the DefaultApiVersion is not reflected in the generated openapi specification. Here's the full program.cs, in which I've double defined the default version just to showcase:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();
builder.Services.AddApiVersioning(o => o.DefaultApiVersion = new(1, 0))
.AddApiExplorer(o=> //without ApiExplorer nothing about the versions is added to the specification
{
    o.DefaultApiVersion = new(1, 0);
    o.GroupNameFormat = "'v'VVV";
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

var v1 = app.NewVersionedApi();

v1.MapGet("/weatherforecast", () =>
    {
        var forecast = Enumerable.Range(1, 5).Select(index =>
                new WeatherForecast
                (
                    DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                    Random.Shared.Next(-20, 55),
                    summaries[Random.Shared.Next(summaries.Length)]
                ))
            .ToArray();
        return forecast;
    })
    .WithName("GetWeatherForecast")
    .HasApiVersion(1,0);

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Generates this openapi.json:

{
  "openapi": "3.0.1",
  "info": {
    "title": "VersionTest | v1",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://localhost:7022"
    },
    {
      "url": "http://localhost:5178"
    }
  ],
  "paths": {
    "/weatherforecast": {
      "get": {
        "tags": [
          "VersionTest"
        ],
        "operationId": "GetWeatherForecast",
        "parameters": [
          {
            "name": "api-version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WeatherForecast"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WeatherForecast": {
        "required": [
          "date",
          "temperatureC",
          "summary"
        ],
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "temperatureC": {
            "type": "integer",
            "format": "int32"
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "temperatureF": {
            "type": "integer",
            "format": "int32"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "VersionTest"
    }
  ]
}

Expected Behavior

The DefaultApiVersion value should be added to the openapi file, which would simplify using e.g. Swagger or Scalar for API exploration.

Steps To Reproduce

https://github.com/spaasis/api-versioning-repro

Exceptions (if any)

No response

.NET Version

No response

Anything else?

No response

spaasis avatar Apr 29 '25 07:04 spaasis

A workaround is to add a transformer:

    services.AddOpenApi(opt => {
        opt.AddDocumentTransformer((document, _, _) => {
            foreach (var parameter in document.Paths.Values.SelectMany(v => v.Operations.Values).SelectMany(v => v.Parameters)) {
                if (parameter.Name == "api-version") {
                    parameter.Schema!.Default = new OpenApiString("1.0");
                }
            }

spaasis avatar May 13 '25 11:05 spaasis