Added more security and metrics

This commit is contained in:
2026-06-22 07:28:03 +02:00
committed by Jeroen Saey
parent 2a1f7b77ee
commit cb2d111ad7
27 changed files with 1638 additions and 884 deletions
@@ -1,7 +1,5 @@
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using EonaCat.DoxaApi.Generation;
using EonaCat.DoxaApi.Interop;
using EonaCat.DoxaApi.Models;
@@ -10,6 +8,8 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using EonaCat.Json;
using EonaCat.Json.Linq;
namespace EonaCat.DoxaApi.Middleware
{
@@ -18,16 +18,17 @@ namespace EonaCat.DoxaApi.Middleware
public static class DoxaApiMiddlewareExtensions
{
private static readonly JsonSerializerOptions _writeOptions = new()
private static readonly JsonSerializerSettings _writeOptions = new()
{
WriteIndented = true,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
public static IApplicationBuilder UseDoxaApi(this IApplicationBuilder app, Action<DoxaApiOptions>? configure = null)
{
var options = app.ApplicationServices.GetService<DoxaApiOptions>() ?? new DoxaApiOptions();
var metricsCollector = app.ApplicationServices.GetService<MetricsCollector>();
configure?.Invoke(options);
var prefix = "/" + options.RoutePrefix.Trim('/');
@@ -38,7 +39,8 @@ namespace EonaCat.DoxaApi.Middleware
{
var document = GenerateDocument(context, options);
context.Response.ContentType = "application/json; charset=utf-8";
await JsonSerializer.SerializeAsync(context.Response.Body, document, _writeOptions);
var json = JsonHelper.ToJson(document, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
});
});
@@ -49,8 +51,8 @@ namespace EonaCat.DoxaApi.Middleware
var document = GenerateDocument(context, options);
var openApi = OpenApiExporter.Export(document);
context.Response.ContentType = "application/json; charset=utf-8";
await context.Response.WriteAsync(
openApi.ToJsonString(_writeOptions), Encoding.UTF8);
var json = JsonHelper.ToJson(openApi, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
});
});
@@ -61,8 +63,8 @@ namespace EonaCat.DoxaApi.Middleware
var document = GenerateDocument(context, options);
var swagger = SwaggerExporter.Export(document);
context.Response.ContentType = "application/json; charset=utf-8";
await context.Response.WriteAsync(
swagger.ToJsonString(_writeOptions), Encoding.UTF8);
var json = JsonHelper.ToJson(swagger, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
});
});
@@ -89,7 +91,8 @@ namespace EonaCat.DoxaApi.Middleware
{
var imported = await OpenApiImporter.ImportAsync(context.Request.Body);
context.Response.ContentType = "application/json; charset=utf-8";
await JsonSerializer.SerializeAsync(context.Response.Body, imported, _writeOptions);
var json = JsonHelper.ToJson(imported, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
}
catch (NotSupportedException ex)
{
@@ -138,7 +141,8 @@ namespace EonaCat.DoxaApi.Middleware
context.Response.StatusCode = int.TryParse(successResponse?.StatusCode, out var code) ? code : 200;
context.Response.ContentType = "application/json; charset=utf-8";
context.Response.Headers["X-DoxaApi-Mock"] = "true";
await JsonSerializer.SerializeAsync(context.Response.Body, mockValue, _writeOptions);
var json = JsonHelper.ToJson(mockValue, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
});
});
}
@@ -199,6 +203,29 @@ namespace EonaCat.DoxaApi.Middleware
});
});
// Add analytics endpoint if metrics collector is registered
if (metricsCollector != null)
{
app.Map(prefix + "/analytics", analyticsApp =>
{
analyticsApp.Run(async context =>
{
if (!HttpMethods.IsGet(context.Request.Method))
{
context.Response.StatusCode = 405;
context.Response.Headers["Allow"] = "GET";
await context.Response.WriteAsync("Method Not Allowed - use GET");
return;
}
var dashboard = metricsCollector.GetDashboard();
context.Response.ContentType = "application/json; charset=utf-8";
var json = JsonHelper.ToJson(dashboard, _writeOptions);
await context.Response.WriteAsync(json, Encoding.UTF8);
});
});
}
return app;
}