using Asp.Versioning; using Asp.Versioning.ApiExplorer; using Microsoft.Extensions.Options; using Swashbuckle.AspNetCore.SwaggerGen; using TarninaHub.Application.Abstractions; using TarninaHub.Configuration; using TarninaHub.Errors; using TarninaHub.Infrastructure; var builder = WebApplication.CreateBuilder(args); // Layered infrastructure: SurrealDB client, settings and persistence services. builder.Services.AddInfrastructure(builder.Configuration); builder.Services.AddControllers(); // Uniform error responses (RFC 7807) and a global exception handler. builder.Services.AddProblemDetails(); builder.Services.AddExceptionHandler(); // API versioning: `?api-version=1.0` or header `X-Api-Version`; default 1.0. builder.Services .AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ApiVersionReader = ApiVersionReader.Combine( new QueryStringApiVersionReader("api-version"), new HeaderApiVersionReader("X-Api-Version")); options.ReportApiVersions = true; }) .AddMvc() .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); // OpenAPI document + Swagger UI (Swashbuckle), one document per API version. builder.Services.AddEndpointsApiExplorer(); builder.Services.AddTransient, ConfigureSwaggerOptions>(); builder.Services.AddSwaggerGen(); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var migrationRunner = scope.ServiceProvider.GetRequiredService(); var storageService = scope.ServiceProvider.GetRequiredService(); await migrationRunner.ApplyAsync(CancellationToken.None); await storageService.InitializeAsync(CancellationToken.None); } app.UseExceptionHandler(); app.UseStatusCodePages(); app.UseSwagger(); app.UseSwaggerUI(options => { var provider = app.Services.GetRequiredService(); foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerEndpoint( $"/swagger/{description.GroupName}/swagger.json", $"TarninaHub API {description.GroupName.ToUpperInvariant()}"); } }); if (!app.Environment.IsDevelopment()) { app.UseHttpsRedirection(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.MapControllers(); app.MapFallbackToFile("index.html"); app.Run();