0

I have a C# / ASP.NET Core Minimal API app with Swagger generating an OpenAPI spec. In order to match the publish yml, I need to add a server with path and remove the path elements from individual groups.

In Program.cs I configure the generator with this code:

.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "My API",
        Version = "2.0",
    });

    c.AddServer(new OpenApiServer
    {
        Url = "https://api.myapi.org.uk/api/v2",
        Description = "Production"
    });

    c.AddServer(new OpenApiServer
    {
        Url = "https://localhost:{port}/api/v2",
        Description = "Local",
        Variables =
        {
            new ("port", new OpenApiServerVariable
            {
                Default = "7147",
            }),
        },
    });
})

Then later map an endpoint in a group like:

var builder = app.MapGroup("/needs");
builder .MapGet("/", async (CancellationToken cancellationToken) => { ... });

When I try to test this with the Swagger UI, I get a 404 response. But if I move the path from the server to the group it works just fine.

.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "My API",
            Version = "2.0",
        });

        c.AddServer(new OpenApiServer
        {
            Url = "https://api.myapi.org.uk/",
            Description = "Production"
        });

        c.AddServer(new OpenApiServer
        {
            Url = "https://localhost:{port}/",
            Description = "Local",
            Variables =
            {
                new ("port", new OpenApiServerVariable
                {
                    Default = "7147",
                }),
            },
        });
    })

// ...

var builder = app.MapGroup("/api/v2/needs");
builder .MapGet("/", async (CancellationToken cancellationToken) => { ... });

I've tried lots of combinations but can't figure out what is wrong. Does this just happen to be part of the spec that isn't implemented correctly or is there a way to make it work?

Ultimately the generated definition needs to looks like

openapi: 3.0.1
info:
  title: My API
  version: '2.0'
servers:
  - url: https://myapi.org.uk/api/v2
    description: Production
  - url: 'https://localhost:{port}'
    description: Local
    variables:
      port:
        default: '7147'

paths:
  /needs:
    get:
      ...

1 Answer 1

1

We should use app.UsePathBaseto fix the issue. Here is my test code.

Microsoft.AspNetCore.OpenApi package is needed.

using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.OpenApi;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "My API",
        Version = "2.0",
    });

    c.AddServer(new OpenApiServer
    {
        Url = "https://api.myapi.org.uk/api/v2",
        Description = "Production"
    });

    c.AddServer(new OpenApiServer
    {
        Url = "https://localhost:{port}/api/v2",
        Description = "Local",
        Variables =
        {
            ["port"] = new OpenApiServerVariable
            {
                Default = "7147",
            }
        }
    });
});


var app = builder.Build();

app.UsePathBase("/api/v2");
app.UseRouting();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API v1");
    });
}

app.UseHttpsRedirection();

app.UseAuthorization();

var needsGroup = app.MapGroup("/needs");
needsGroup.MapGet("/", () => "Hello from Needs API!")
    .WithOpenApi();

app.Run();

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.