using System.Text.RegularExpressions; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Shared.Contracts.Generated; using Shared.Problems; using Swashbuckle.AspNetCore.SwaggerGen; namespace Shared.Contracts; public static class KbxApiContractSwaggerExtensions { public static void AddKbxApiContracts(this SwaggerGenOptions options) { options.OperationFilter(); options.OperationFilter(); } } public sealed class KbxApiContractOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var method = context.ApiDescription.HttpMethod?.ToUpperInvariant(); var relative = "/" + (context.ApiDescription.RelativePath ?? string.Empty).TrimStart('/'); var normalized = Normalize(relative); var contract = KbxApiCatalog.All.FirstOrDefault(x => x.Method == method && Normalize(x.Path) == normalized); if (contract is null) return; operation.OperationId = contract.Id; operation.Extensions["x-kbx-permission"] = new OpenApiString(contract.Permission ?? string.Empty); operation.Extensions["x-kbx-idempotency"] = new OpenApiString(contract.Idempotency); operation.Extensions["x-kbx-kind"] = new OpenApiString(contract.Kind); } private static string Normalize(string value) => Regex.Replace(value, @"\{([^}:]+):[^}]+\}", "{$1}").ToLowerInvariant(); } public sealed class KbxProblemOpenApiOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var problem = new OpenApiSchema { OneOf = new List { context.SchemaGenerator.GenerateSchema(typeof(KbxValidationProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxBusinessProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxConflictProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxPermissionProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxNotFoundProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxIntegrationProblem), context.SchemaRepository), context.SchemaGenerator.GenerateSchema(typeof(KbxSystemProblem), context.SchemaRepository), } }; Add(operation, "400", "Validation problem", problem); Add(operation, "403", "Permission problem", problem); Add(operation, "404", "Not found problem", problem); Add(operation, "409", "Conflict or business rule problem", problem); Add(operation, "422", "Business rule problem", problem); Add(operation, "500", "System problem", problem); } private static void Add(OpenApiOperation operation, string status, string description, OpenApiSchema schema) { if (operation.Responses.ContainsKey(status)) return; operation.Responses[status] = new OpenApiResponse { Description = description, Content = new Dictionary { ["application/json"] = new() { Schema = schema } } }; } }