using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using StickyBoard.Core.DTOs.Common;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace StickyBoard.Api.Common.Filters
{
///
/// Ensures standard error responses are documented for all endpoints.
/// Adds consistent schema + example error payloads for API consumers.
///
public sealed class DefaultResponsesOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// Generate shared schema for ErrorDto
var errorSchema = context.SchemaGenerator.GenerateSchema(typeof(ErrorDto), context.SchemaRepository);
// Common error response example structure
OpenApiMediaType ExampleError(string code, string message)
{
return new OpenApiMediaType
{
Schema = errorSchema,
Example = new OpenApiObject
{
["code"] = new OpenApiString(code),
["message"] = new OpenApiString(message),
["details"] = new OpenApiString("Additional debug info in development mode only")
}
};
}
// Standard HTTP Error responses to attach
var standardErrors = new Dictionary
{
["400"] = ("Bad Request", ExampleError("VALIDATION_ERROR", "Invalid input")),
["401"] = ("Unauthorized", ExampleError("AUTH_INVALID", "Authentication required or invalid token")),
["403"] = ("Forbidden", ExampleError("FORBIDDEN", "User does not have access to this resource")),
["404"] = ("Not Found", ExampleError("NOT_FOUND", "Requested resource does not exist")),
["500"] = ("Internal Server Error", ExampleError("SERVER_ERROR", "Unexpected server error"))
};
foreach (var entry in standardErrors)
{
if (!operation.Responses.ContainsKey(entry.Key))
{
operation.Responses.Add(
entry.Key,
new OpenApiResponse
{
Description = entry.Value.description,
Content = new Dictionary
{
["application/json"] = entry.Value.example
}
}
);
}
}
}
}
}