feat(api): Enable conditional Swagger/Scalar in production

Program.cs changes:
- Add Scalar.AspNetCore using
- Register SwaggerSettings with Options Pattern
- Pass IConfiguration to AddSwaggerDocumentation()
- Conditional middleware: Development OR EnableInProduction=true
- Add Swagger UI with custom endpoint configuration
- Add Scalar UI at /scalar/v1 (DeepSpace theme, C# HttpClient target)

Access URLs:
- Swagger UI: https://localhost:7186/swagger
- Scalar UI: https://localhost:7186/scalar/v1
- Serilog UI: https://localhost:7186/serilog-ui

Production behavior: Swagger+Scalar enabled by default (configurable)
This commit is contained in:
2026-07-21 15:01:56 +02:00
parent 06a9dc7385
commit 2804993ea6

View File

@@ -2,6 +2,7 @@ using Serilog;
using Serilog.Ui.Core.Extensions; using Serilog.Ui.Core.Extensions;
using Serilog.Ui.SqliteDataProvider.Extensions; using Serilog.Ui.SqliteDataProvider.Extensions;
using Serilog.Ui.Web.Extensions; using Serilog.Ui.Web.Extensions;
using Scalar.AspNetCore;
using DocumentOperator.Infrastructure.Configuration; using DocumentOperator.Infrastructure.Configuration;
using DocumentOperator.Application; using DocumentOperator.Application;
using DocumentOperator.Infrastructure; using DocumentOperator.Infrastructure;
@@ -37,6 +38,9 @@ try
builder.Services.Configure<ApiKeySettings>( builder.Services.Configure<ApiKeySettings>(
builder.Configuration.GetSection(ApiKeySettings.SectionName)); builder.Configuration.GetSection(ApiKeySettings.SectionName));
builder.Services.Configure<SwaggerSettings>(
builder.Configuration.GetSection(SwaggerSettings.SectionName));
// ======================================== // ========================================
// 3. Services (Clean Architecture Layers) // 3. Services (Clean Architecture Layers)
// ======================================== // ========================================
@@ -45,7 +49,7 @@ try
builder.Services.AddControllers(); // Controllers (Controller-based API) builder.Services.AddControllers(); // Controllers (Controller-based API)
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerDocumentation(); builder.Services.AddSwaggerDocumentation(builder.Configuration);
// ======================================== // ========================================
// 4. Serilog.UI Configuration // 4. Serilog.UI Configuration
@@ -75,10 +79,32 @@ try
// Exception Handling FIRST (catches all exceptions from subsequent middleware) // Exception Handling FIRST (catches all exceptions from subsequent middleware)
app.UseMiddleware<ExceptionHandlingMiddleware>(); app.UseMiddleware<ExceptionHandlingMiddleware>();
if (app.Environment.IsDevelopment()) // ========================================
// Swagger/OpenAPI (Conditional based on settings)
// ========================================
var swaggerSettings = builder.Configuration.GetSection(SwaggerSettings.SectionName).Get<SwaggerSettings>()
?? new SwaggerSettings();
if (app.Environment.IsDevelopment() || swaggerSettings.EnableInProduction)
{ {
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI();
// Swagger UI (classic)
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint($"/swagger/{swaggerSettings.Version}/swagger.json",
$"{swaggerSettings.Title} {swaggerSettings.Version}");
options.RoutePrefix = "swagger"; // /swagger
});
// Scalar UI (modern alternative)
app.MapScalarApiReference(options =>
{
options
.WithTitle(swaggerSettings.Title)
.WithTheme(ScalarTheme.DeepSpace)
.WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient);
});
} }
app.UseSerilogRequestLogging(); // Log HTTP Requests app.UseSerilogRequestLogging(); // Log HTTP Requests