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
+67
View File
@@ -0,0 +1,67 @@
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
/// <summary>
/// Analytics dashboard data containing metrics and insights.
/// </summary>
public class AnalyticsDashboard
{
[JsonProperty("totalEndpoints")]
public int TotalEndpoints { get; set; }
[JsonProperty("totalRequests")]
public int TotalRequests { get; set; }
[JsonProperty("totalErrors")]
public int TotalErrors { get; set; }
[JsonProperty("averageResponseTime")]
public double AverageResponseTime { get; set; }
[JsonProperty("peakRequestsPerSecond")]
public double PeakRequestsPerSecond { get; set; }
[JsonProperty("uptime")]
public TimeSpan Uptime { get; set; }
[JsonProperty("topEndpoints")]
public List<EndpointUsageSummary> TopEndpoints { get; set; } = new();
[JsonProperty("recentRequests")]
public List<RequestMetadata> RecentRequests { get; set; } = new();
[JsonProperty("errorRate")]
public double ErrorRate { get; set; }
[JsonProperty("generatedAt")]
public DateTime GeneratedAt { get; set; } = DateTime.UtcNow;
}
/// <summary>
/// Summary of endpoint usage for dashboard display.
/// </summary>
public class EndpointUsageSummary
{
[JsonProperty("method")]
public string Method { get; set; } = string.Empty;
[JsonProperty("path")]
public string Path { get; set; } = string.Empty;
[JsonProperty("requestCount")]
public int RequestCount { get; set; }
[JsonProperty("errorCount")]
public int ErrorCount { get; set; }
[JsonProperty("averageResponseTimeMs")]
public double AverageResponseTimeMs { get; set; }
[JsonProperty("lastCalled")]
public DateTime? LastCalled { get; set; }
}
}
+7 -7
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,24 +7,24 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiDocument
{
[JsonPropertyName("info")]
[JsonProperty("info")]
public ApiInfo Info { get; set; } = new();
[JsonPropertyName("servers")]
[JsonProperty("servers")]
public List<string> Servers { get; set; } = new();
[JsonPropertyName("groups")]
[JsonProperty("groups")]
public List<ApiGroup> Groups { get; set; } = new();
[JsonPropertyName("schemas")]
[JsonProperty("schemas")]
public Dictionary<string, SchemaModel> Schemas { get; set; } = new();
/// <summary>All security schemes available for this API (keyed by scheme id).</summary>
[JsonPropertyName("securitySchemes")]
[JsonProperty("securitySchemes")]
public Dictionary<string, SecuritySchemeModel> SecuritySchemes { get; set; } = new();
/// <summary>Which optional DoxaApi server-side features are enabled, for UI feature detection.</summary>
[JsonPropertyName("features")]
[JsonProperty("features")]
public ApiFeatureFlags Features { get; set; } = new();
}
}
+12 -12
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,41 +7,41 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiEndpoint
{
[JsonPropertyName("operationId")]
[JsonProperty("operationId")]
public string OperationId { get; set; } = "";
[JsonPropertyName("summary")]
[JsonProperty("summary")]
public string? Summary { get; set; }
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
[JsonPropertyName("method")]
[JsonProperty("method")]
public string Method { get; set; } = "GET";
[JsonPropertyName("path")]
[JsonProperty("path")]
public string Path { get; set; } = "/";
[JsonPropertyName("deprecated")]
[JsonProperty("deprecated")]
public bool Deprecated { get; set; }
[JsonPropertyName("tags")]
[JsonProperty("tags")]
public List<string> Tags { get; set; } = new();
[JsonPropertyName("parameters")]
[JsonProperty("parameters")]
public List<ApiParameter> Parameters { get; set; } = new();
[JsonPropertyName("requestBody")]
[JsonProperty("requestBody")]
public RequestBodyModel? RequestBody { get; set; }
[JsonPropertyName("responses")]
[JsonProperty("responses")]
public List<ResponseModel> Responses { get; set; } = new();
/// <summary>
/// Ids of security schemes that apply to this endpoint (referencing ApiDocument.SecuritySchemes).
/// Empty means the endpoint is unauthenticated (or uses the document-wide default, if any).
/// </summary>
[JsonPropertyName("security")]
[JsonProperty("security")]
public List<string> Security { get; set; } = new();
}
}
+3 -3
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,10 +7,10 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiFeatureFlags
{
[JsonPropertyName("mockServer")]
[JsonProperty("mockServer")]
public bool MockServer { get; set; }
[JsonPropertyName("console")]
[JsonProperty("console")]
public bool Console { get; set; }
}
}
+4 -4
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,13 +7,13 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiGroup
{
[JsonPropertyName("name")]
[JsonProperty("name")]
public string Name { get; set; } = "";
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
[JsonPropertyName("endpoints")]
[JsonProperty("endpoints")]
public List<ApiEndpoint> Endpoints { get; set; } = new();
}
}
+4 -4
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,13 +7,13 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiInfo
{
[JsonPropertyName("title")]
[JsonProperty("title")]
public string Title { get; set; } = "API Documentation";
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
[JsonPropertyName("version")]
[JsonProperty("version")]
public string Version { get; set; } = "v1";
}
}
+46
View File
@@ -0,0 +1,46 @@
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
/// <summary>
/// Tracks metrics and statistics for API endpoints.
/// </summary>
public class ApiMetrics
{
[JsonProperty("endpointId")]
public string EndpointId { get; set; } = string.Empty;
[JsonProperty("method")]
public string Method { get; set; } = string.Empty;
[JsonProperty("path")]
public string Path { get; set; } = string.Empty;
[JsonProperty("totalRequests")]
public int TotalRequests { get; set; }
[JsonProperty("successfulRequests")]
public int SuccessfulRequests { get; set; }
[JsonProperty("failedRequests")]
public int FailedRequests { get; set; }
[JsonProperty("averageResponseTimeMs")]
public double AverageResponseTimeMs { get; set; }
[JsonProperty("lastRequestAt")]
public DateTime? LastRequestAt { get; set; }
[JsonProperty("createdAt")]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
[JsonProperty("statusCodes")]
public Dictionary<int, int> StatusCodes { get; set; } = new();
[JsonProperty("averageResponseSize")]
public long AverageResponseSize { get; set; }
}
}
+7 -7
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,22 +7,22 @@ namespace EonaCat.DoxaApi.Models
public sealed class ApiParameter
{
[JsonPropertyName("name")]
[JsonProperty("name")]
public string Name { get; set; } = "";
[JsonPropertyName("in")]
[JsonProperty("in")]
public string In { get; set; } = "query";
[JsonPropertyName("required")]
[JsonProperty("required")]
public bool Required { get; set; }
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
[JsonPropertyName("schema")]
[JsonProperty("schema")]
public SchemaModel Schema { get; set; } = new();
[JsonPropertyName("default")]
[JsonProperty("default")]
public object? Default { get; set; }
}
}
+5 -5
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,16 +7,16 @@ namespace EonaCat.DoxaApi.Models
public sealed class RequestBodyModel
{
[JsonPropertyName("required")]
[JsonProperty("required")]
public bool Required { get; set; }
[JsonPropertyName("contentType")]
[JsonProperty("contentType")]
public string ContentType { get; set; } = "application/json";
[JsonPropertyName("schema")]
[JsonProperty("schema")]
public SchemaModel Schema { get; set; } = new();
[JsonPropertyName("example")]
[JsonProperty("example")]
public string? Example { get; set; }
}
}
+46
View File
@@ -0,0 +1,46 @@
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
/// <summary>
/// Metadata for tracking requests and responses.
/// </summary>
public class RequestMetadata
{
[JsonProperty("id")]
public string Id { get; set; } = Guid.NewGuid().ToString();
[JsonProperty("method")]
public string Method { get; set; } = string.Empty;
[JsonProperty("path")]
public string Path { get; set; } = string.Empty;
[JsonProperty("statusCode")]
public int StatusCode { get; set; }
[JsonProperty("responseTimeMs")]
public long ResponseTimeMs { get; set; }
[JsonProperty("requestSize")]
public long RequestSize { get; set; }
[JsonProperty("responseSize")]
public long ResponseSize { get; set; }
[JsonProperty("timestamp")]
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
[JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)]
public string? UserAgent { get; set; }
[JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)]
public string? IpAddress { get; set; }
[JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)]
public string? Error { get; set; }
}
}
+4 -4
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,13 +7,13 @@ namespace EonaCat.DoxaApi.Models
public sealed class ResponseModel
{
[JsonPropertyName("statusCode")]
[JsonProperty("statusCode")]
public string StatusCode { get; set; } = "200";
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
[JsonPropertyName("schema")]
[JsonProperty("schema")]
public SchemaModel? Schema { get; set; }
}
}
+9 -9
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -7,28 +7,28 @@ namespace EonaCat.DoxaApi.Models
public sealed class SchemaModel
{
[JsonPropertyName("type")]
[JsonProperty("type")]
public string Type { get; set; } = "object";
[JsonPropertyName("format")]
[JsonProperty("format")]
public string? Format { get; set; }
[JsonPropertyName("refName")]
[JsonProperty("refName")]
public string? RefName { get; set; }
[JsonPropertyName("items")]
[JsonProperty("items")]
public SchemaModel? Items { get; set; }
[JsonPropertyName("properties")]
[JsonProperty("properties")]
public Dictionary<string, SchemaModel>? Properties { get; set; }
[JsonPropertyName("required")]
[JsonProperty("required")]
public List<string>? Required { get; set; }
[JsonPropertyName("enumValues")]
[JsonProperty("enumValues")]
public List<string>? EnumValues { get; set; }
[JsonPropertyName("nullable")]
[JsonProperty("nullable")]
public bool Nullable { get; set; }
}
}
+17 -17
View File
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using EonaCat.Json;
namespace EonaCat.DoxaApi.Models
{
@@ -13,64 +13,64 @@ namespace EonaCat.DoxaApi.Models
/// </summary>
public sealed class SecuritySchemeModel
{
[JsonPropertyName("id")]
[JsonProperty("id")]
public string Id { get; set; } = "";
/// <summary>apiKey | http | oauth2 | openIdConnect</summary>
[JsonPropertyName("type")]
[JsonProperty("type")]
public string Type { get; set; } = "apiKey";
[JsonPropertyName("description")]
[JsonProperty("description")]
public string? Description { get; set; }
/// <summary>For apiKey: header | query | cookie</summary>
[JsonPropertyName("in")]
[JsonProperty("in")]
public string? In { get; set; }
/// <summary>For apiKey: the header/query/cookie name. For http: ignored.</summary>
[JsonPropertyName("name")]
[JsonProperty("name")]
public string? Name { get; set; }
/// <summary>For http: bearer | basic | digest</summary>
[JsonPropertyName("scheme")]
[JsonProperty("scheme")]
public string? Scheme { get; set; }
/// <summary>For http bearer: an informational hint such as "JWT".</summary>
[JsonPropertyName("bearerFormat")]
[JsonProperty("bearerFormat")]
public string? BearerFormat { get; set; }
/// <summary>For oauth2: supported flows (clientCredentials, authorizationCode, password, implicit).</summary>
[JsonPropertyName("flows")]
[JsonProperty("flows")]
public OAuthFlowsModel? Flows { get; set; }
}
public sealed class OAuthFlowsModel
{
[JsonPropertyName("clientCredentials")]
[JsonProperty("clientCredentials")]
public OAuthFlowModel? ClientCredentials { get; set; }
[JsonPropertyName("authorizationCode")]
[JsonProperty("authorizationCode")]
public OAuthFlowModel? AuthorizationCode { get; set; }
[JsonPropertyName("password")]
[JsonProperty("password")]
public OAuthFlowModel? Password { get; set; }
[JsonPropertyName("implicit")]
[JsonProperty("implicit")]
public OAuthFlowModel? Implicit { get; set; }
}
public sealed class OAuthFlowModel
{
[JsonPropertyName("authorizationUrl")]
[JsonProperty("authorizationUrl")]
public string? AuthorizationUrl { get; set; }
[JsonPropertyName("tokenUrl")]
[JsonProperty("tokenUrl")]
public string? TokenUrl { get; set; }
[JsonPropertyName("refreshUrl")]
[JsonProperty("refreshUrl")]
public string? RefreshUrl { get; set; }
[JsonPropertyName("scopes")]
[JsonProperty("scopes")]
public Dictionary<string, string> Scopes { get; set; } = new();
}
}