using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; namespace MoShiro.Backend.Api; public static class EndpointConventions { /// 每个端点都必须有 operationId(snake_case,资源_动作)、summary 和 tag。 public static RouteHandlerBuilder Api(this RouteHandlerBuilder builder, string operationId, string summary, string tag) => builder.WithName(operationId).WithSummary(summary).WithTags(tag); /// 声明端点需要的能力(授权的唯一依据);OpenAPI 里带上 x-moshiro-capability。 public static RouteHandlerBuilder Requires(this RouteHandlerBuilder builder, string capability) => builder.WithMetadata(new CapabilityRequirement(capability)).AddOpenApiOperationTransformer((operation, _, _) => { operation.Extensions ??= new Dictionary(); operation.Extensions["x-moshiro-capability"] = new Microsoft.OpenApi.JsonNodeExtension(System.Text.Json.Nodes.JsonValue.Create(capability)); return Task.CompletedTask; }); /// 匿名可访问的管理端点(登录):显式声明,对账测试才能区分「忘了声明」。 public static RouteHandlerBuilder AllowsAnonymous(this RouteHandlerBuilder builder) => builder.WithMetadata(new CapabilityRequirement(null)); public static RouteHandlerBuilder Returns(this RouteHandlerBuilder builder, int status = StatusCodes.Status200OK) => builder.Produces(status); /// 登记该端点可能返回的错误状态(problem+json),让 OpenAPI 文档完整。 public static RouteHandlerBuilder ProducesProblems(this RouteHandlerBuilder builder, params int[] statuses) { foreach (int status in statuses) { builder.Produces(status, Problems.ContentType); } return builder; } }