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);
}