Files
ersatztv/ErsatzTV/Serialization/ValidationProblemOperationTransformer.cs
T
timothyandClaude Opus 4.8 171364d0e8 feat(api): #287 OpenAPI contract honesty by construction
ApiKey security scheme + per-op security/401 via shared EndpointRequiresKey
predicate (no drift from enforcement); synthesized stable operationIds;
400 ValidationProblemDetails on binding ops; DayOfWeek as string enum.

Refs #287 #197

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 02:08:12 +02:00

53 lines
1.9 KiB
C#

#nullable enable
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
namespace ErsatzTV.Serialization;
/// <summary>
/// OpenAPI operation transformer that documents the <c>400</c> a model-binding / FluentValidation
/// failure actually returns. ASP.NET Core's <c>[ApiController]</c> convention emits a
/// <c>ValidationProblemDetails</c> (an <c>errors</c> map) for any operation that binds a request body
/// or parameters, but that response was undocumented. This adds a <c>400</c> referencing the
/// <c>ValidationProblemDetails</c> schema (declared by
/// <see cref="ApiSecuritySchemeDocumentTransformer" />) to every operation that binds something and
/// does not already document a <c>400</c>. See issues #286/#287.
/// </summary>
public static class ValidationProblemOperationTransformer
{
public static Task TransformAsync(
OpenApiOperation operation,
OpenApiOperationTransformerContext context,
CancellationToken cancellationToken)
{
bool bindsSomething = operation.RequestBody is not null
|| operation.Parameters is { Count: > 0 };
if (!bindsSomething)
{
return Task.CompletedTask;
}
operation.Responses ??= new OpenApiResponses();
if (operation.Responses.ContainsKey("400"))
{
return Task.CompletedTask;
}
operation.Responses["400"] = new OpenApiResponse
{
Description = "Request validation failed (model binding or FluentValidation).",
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType
{
Schema = new OpenApiSchemaReference(
ApiSecuritySchemeDocumentTransformer.ValidationProblemDetailsSchemaId)
}
}
};
return Task.CompletedTask;
}
}