using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.OpenApi; using Microsoft.OpenApi; namespace Nexus.Api.Http; /// /// Publishes the stable Nexus ProblemDetails extensions in the generated /// OpenAPI contract so the frontend does not have to guess error metadata. /// public sealed class NexusProblemDetailsSchemaTransformer : IOpenApiSchemaTransformer { public Task TransformAsync( OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken) { if (!typeof(ProblemDetails).IsAssignableFrom(context.JsonTypeInfo.Type)) return Task.CompletedTask; schema.Properties ??= new Dictionary(); schema.Properties["code"] = StringSchema( "Stable machine-readable Nexus error code."); schema.Properties["traceId"] = StringSchema( "Privacy-safe server trace identifier."); schema.Properties["operationId"] = StringSchema( "Durable operation identifier when the request started an operation."); schema.Properties["currentRevision"] = IntegerSchema( "Current server revision for a stale-write conflict."); schema.Properties["retryAfterSeconds"] = IntegerSchema( "Minimum retry delay advertised by Nexus."); schema.Properties["remaining"] = IntegerSchema( "Remaining attempts when a bounded policy exposes that value."); schema.Properties["expectedHash"] = StringSchema( "Client-supplied content hash for a stale-write conflict."); schema.Properties["currentHash"] = StringSchema( "Current server content hash for a stale-write conflict."); schema.Required ??= new HashSet(); schema.Required.Add("code"); schema.Required.Add("traceId"); return Task.CompletedTask; } private static OpenApiSchema StringSchema(string description) => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Description = description }; private static OpenApiSchema IntegerSchema(string description) => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32", Description = description }; }