From 2804993ea638eab1a465e65bc2e44b5906e6a6fb Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 21 Jul 2026 15:01:56 +0200 Subject: [PATCH] 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) --- DocumentOperator.API/Program.cs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/DocumentOperator.API/Program.cs b/DocumentOperator.API/Program.cs index cd7b19c..5492a1f 100644 --- a/DocumentOperator.API/Program.cs +++ b/DocumentOperator.API/Program.cs @@ -2,6 +2,7 @@ using Serilog; using Serilog.Ui.Core.Extensions; using Serilog.Ui.SqliteDataProvider.Extensions; using Serilog.Ui.Web.Extensions; +using Scalar.AspNetCore; using DocumentOperator.Infrastructure.Configuration; using DocumentOperator.Application; using DocumentOperator.Infrastructure; @@ -37,6 +38,9 @@ try builder.Services.Configure( builder.Configuration.GetSection(ApiKeySettings.SectionName)); + builder.Services.Configure( + builder.Configuration.GetSection(SwaggerSettings.SectionName)); + // ======================================== // 3. Services (Clean Architecture Layers) // ======================================== @@ -45,7 +49,7 @@ try builder.Services.AddControllers(); // Controllers (Controller-based API) builder.Services.AddEndpointsApiExplorer(); - builder.Services.AddSwaggerDocumentation(); + builder.Services.AddSwaggerDocumentation(builder.Configuration); // ======================================== // 4. Serilog.UI Configuration @@ -75,10 +79,32 @@ try // Exception Handling FIRST (catches all exceptions from subsequent middleware) app.UseMiddleware(); - if (app.Environment.IsDevelopment()) + // ======================================== + // Swagger/OpenAPI (Conditional based on settings) + // ======================================== + var swaggerSettings = builder.Configuration.GetSection(SwaggerSettings.SectionName).Get() + ?? new SwaggerSettings(); + + if (app.Environment.IsDevelopment() || swaggerSettings.EnableInProduction) { 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