diff --git a/App/Api/Api.csproj b/App/Api/Api.csproj index 5547bb1..3bc636e 100644 --- a/App/Api/Api.csproj +++ b/App/Api/Api.csproj @@ -3,6 +3,7 @@ + diff --git a/App/Api/Properties/launchSettings.json b/App/Api/Properties/launchSettings.json index 82a585f..238ad46 100644 --- a/App/Api/Properties/launchSettings.json +++ b/App/Api/Properties/launchSettings.json @@ -5,7 +5,7 @@ "hotReloadEnabled": true, "dotnetRunMessages": true, "launchBrowser": true, - "launchUrl": "http://localhost:5000/", + "launchUrl": "http://localhost:5000/scalar", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HTTP_PORTS": "5000" diff --git a/App/Api/Setup/ApiMiddleware.cs b/App/Api/Setup/ApiMiddleware.cs index dae20a3..752e72e 100644 --- a/App/Api/Setup/ApiMiddleware.cs +++ b/App/Api/Setup/ApiMiddleware.cs @@ -1,3 +1,5 @@ +using Scalar.AspNetCore; + namespace Api.Setup; internal static class ApiMiddleware @@ -13,21 +15,23 @@ public static void ConfigureMiddleware(this WebApplication app, IWebHostEnvironm app.UseOutputCache(); - app.UseStaticFiles(); + app.MapOpenApi("/openapi/{documentName}.json"); + + app.UseSwagger(opt => + { + opt.RouteTemplate = "swagger/{documentName}/swagger.json"; + }); - app.UseSwagger(); app.UseSwaggerUI(opt => { - var descriptions = app.DescribeApiVersions(); - foreach (var desc in descriptions) - { - var url = $"/swagger/{desc.GroupName}/swagger.json"; - var name = desc.GroupName.ToUpperInvariant(); - opt.SwaggerEndpoint(url, name); - } - opt.RoutePrefix = string.Empty; - var indexPath = Path.Combine(environment.WebRootPath, "swagger-ui", "index.html"); - opt.IndexStream = () => new FileStream(indexPath, FileMode.Open, FileAccess.Read); + opt.RoutePrefix = "swagger"; + }); + + app.MapScalarApiReference(endpointPrefix: "/scalar", opt => + { + opt.Title = "Bitcoin Web API"; + opt.ShowSidebar = true; + opt.DarkMode = true; }); app.MapHealthChecks("health"); @@ -41,7 +45,6 @@ public static void ConfigureMiddleware(this WebApplication app, IWebHostEnvironm app.Use(async (context, next) => { - context.Response.Headers.Append("Content-Security-Policy", "default-src 'self'"); context.Response.Headers.Append("X-Content-Type-Options", "nosniff"); context.Response.Headers.Append("X-Frame-Options", "DENY"); context.Response.Headers.Append("Referrer-Policy", "no-referrer"); diff --git a/App/Api/Setup/ApiServices.cs b/App/Api/Setup/ApiServices.cs index e48d58d..f7110c1 100644 --- a/App/Api/Setup/ApiServices.cs +++ b/App/Api/Setup/ApiServices.cs @@ -28,9 +28,9 @@ public static void ConfigureServices(this IServiceCollection services) opt.SubstituteApiVersionInUrl = true; }); + services.AddOpenApi(); services.AddSwaggerGen(); - services.ConfigureOptions(); services.Configure(opt => { diff --git a/App/Api/Setup/SwaggerOptions.cs b/App/Api/Setup/SwaggerOptions.cs deleted file mode 100644 index 71cef31..0000000 --- a/App/Api/Setup/SwaggerOptions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Asp.Versioning.ApiExplorer; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace Api.Setup; - -internal sealed class SwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions -{ - private readonly IApiVersionDescriptionProvider _provider = provider; - - public void Configure(SwaggerGenOptions options) - { - foreach (var description in _provider.ApiVersionDescriptions) - { - options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); - } - } - - private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) - { - var info = new OpenApiInfo() - { - Title = "Bitcoin Web API", - Version = description.ApiVersion.ToString(), - Description = "Description of API", - }; - - if (description.IsDeprecated) - { - info.Description += " This API version has been deprecated."; - } - - return info; - } -} diff --git a/App/Api/wwwroot/swagger-ui/index.html b/App/Api/wwwroot/swagger-ui/index.html deleted file mode 100644 index 9a2c709..0000000 --- a/App/Api/wwwroot/swagger-ui/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - %(DocumentTitle) Customized - - - - - %(HeadContent) - - - -
- - - - - \ No newline at end of file diff --git a/App/Directory.Packages.props b/App/Directory.Packages.props index 089dc16..5420ab9 100644 --- a/App/Directory.Packages.props +++ b/App/Directory.Packages.props @@ -9,6 +9,7 @@ + diff --git a/Tests/IntegrationTests/ApiEndpointsTests.cs b/Tests/IntegrationTests/ApiEndpointsTests.cs index 40064d4..ebc6f90 100644 --- a/Tests/IntegrationTests/ApiEndpointsTests.cs +++ b/Tests/IntegrationTests/ApiEndpointsTests.cs @@ -63,9 +63,16 @@ public async Task BuyAndSell(string? fromDate, string? toDate, HttpStatusCode st } [Fact] - public async Task Swagger() + public async Task SwaggerUI() { - var result = await _fixture.Client.GetAsync("/", cancellationToken: TestContext.Current.CancellationToken); + var result = await _fixture.Client.GetAsync("/swagger", cancellationToken: TestContext.Current.CancellationToken); + result.StatusCode.ShouldBe(HttpStatusCode.OK); + } + + [Fact] + public async Task ScalarUI() + { + var result = await _fixture.Client.GetAsync("/scalar", cancellationToken: TestContext.Current.CancellationToken); result.StatusCode.ShouldBe(HttpStatusCode.OK); }