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