Appearance
HTTP Boundary
ASP.NET Core Minimal API
[Required]このreferenceはASP.NET Core Minimal API、HTTP DTO、認証filter、typed result、OpenAPIを扱う。domain modelと配置はarchitecture.md、Handlerはapplication.md、HTTP入力変換はvalidation.md、repositoryはpersistence.md、DIはruntime.mdを正とする。
Route Groups
[Required]Controller ではなく Minimal API を使う。[Required]Area単位でMapGroupを作り、use case endpointをぶら下げる。
csharp
namespace Backend.Features.Customers;
public static class CustomerEndpoints
{
public static RouteGroupBuilder MapCustomerApi(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/customers");
group.MapSignupApi();
return group;
}
}[Required]複数 use case を持つ area はFeatures/{Area}/{Area}Endpoints.csに area route group を置く。[Required]route group は API/resource の主語に合わせる。/rooms/{roomId}:joinのような action route でも、group は/roomsのままにする。[Required]area endpoint は route group を作り、use case endpoint のMap{UseCase}Api()を呼び出すだけにする。[Required]area endpoint に個別 route のMapPost/MapPut/MapDeleteなどや endpoint lambda を直接置かない。[Contextual]Healthzのような単一目的 endpoint はEndpoints.cs/Endpointsを許可する。[Required]Program.csには mapping の 1 行だけを追加する。[Required]Program.csに個別 endpoint を直接書かない。
csharp
app.MapCustomerApi();Use Case Endpoints
[Required]Use case endpoint はFeatures/{Area}/{UseCase}/{Area}{UseCase}Endpoint.csに置く。[Required]AreaとUse Caseの所有境界はarchitecture.mdを正とし、このreferenceではHTTP mappingだけを扱う。[Required]Use case endpoint fileには、そのuse caseのroute mappingとendpoint lambdaを閉じ込める。[Required]request / response / handlerと対応するendpoint fileは同じuse case directoryに置く。
csharp
namespace Backend.Features.Customers.Signup;
public static class CustomerSignupEndpoint
{
public static RouteGroupBuilder MapSignupApi(this RouteGroupBuilder group)
{
group.MapPost("/", async Task<Results<
Created<CustomerSignupResponse>,
ProblemHttpResult>> (
CustomerSignupRequest request,
ApiProblemResults problems,
CustomerSignupHandler handler,
CancellationToken ct) =>
{
var email = Ensure.Valid(EmailAddress.Create(request.Email));
var result = await handler.HandleAsync(email, ct);
if (result.IsError)
{
return problems.FromErrors(result.Errors);
}
var value = result.Value;
var body = new CustomerSignupResponse(
value.CustomerDisplayId,
value.ObjectId,
value.Email.Value);
return TypedResults.Created($"/customers/{body.CustomerDisplayId}", body);
})
.AddEndpointFilter<RequestValidationFilter<CustomerSignupRequest>>();
return group;
}
}[Required]Endpoint lambdaは薄く保つ。[Required]request を受ける。[Required]validation filter を通す。[Required]handler を呼び出す。[Required]handler result を HTTP response に mapping する。
Endpoint lambda に書かないもの:
[Required]業務ロジック。[Required]DB 操作。[Required]複数集約の生成・更新処理。[Required]validator と重複する入力検証。[Required]handler / repository / service の組み立て。
Authentication Filter
[Required]Bearer token検証や認証済みuser解決のような横断的なHTTP認証はendpoint filterに寄せる。[Required]認証が必要なendpointは、endpoint lambda内でtoken検証やuser解決を直接行わず、filterが設定した認証contextから必要な値だけを読む。
csharp
group.MapPost("/", CreateCustomerAsync)
.AddEndpointFilter<AuthenticatedUserFilter>()
.AddEndpointFilter<RequestValidationFilter<CustomerCreateRequest>>();[Required]endpoint lambda 内でVerifyIDTokenAsync、GetUserAsyncなど認証用 service method を直接呼ばない。[Required]filter は認証失敗時にRFC 9457 Problem Detailsの401 responseを返してendpoint本体を実行しない。[Required]endpoint lambda はAuthenticatedUserContextなどの context から認証済み user id / user 情報を読む。[Required]認証 filter 通過後のAuthenticatedUserContext.RequireUID()/RequireUser().UIDは認証 context の契約済み値として扱う。PlayerIdなどの Value Object へ変換するときはEnsure.Valid(...)を使い、失敗時は 400 にせず filter / context の契約違反として扱う。[Required]endpoint filter で route parameter を暗黙変換したりEndpointFilterInvocationContext.Argumentsを差し替えたりしない。filter は認証、validation、context setup、short-circuit response に留める。[Contextual]handler に渡す引数が多い場合は endpoint で{Area}{UseCase}Commandを named arguments で組み立て、handler.HandleAsync(command, ct)を呼ぶ。[Required]display name 更新など use case 固有の外部 service 呼び出しは、認証検証ではないため endpoint または handler の責務として別に扱う。[Contextual]request validation filter と併用する場合は、認証 filter を先に接続する。
request body、route parameter、認証contextからValue Objectへ変換する共通規則と失敗の扱いはvalidation.mdを正とする。
Typed Results
[Required]Response はTypedResultsとMicrosoft.AspNetCore.Http.HttpResults.Results<T1, T2, ...>で型安全に返す。[Required]endpoint の戻り値型には成功 response と想定 error response を列挙する。[Required]Results<T1, T2, ...>は typed union 戻り値型として使う。[Required]成功responseはTypedResults.Ok(...)、TypedResults.Created(...)などを使い、error responseはTypedResults.Problem(...)を使う。[Required]Results.Ok(...)、Results.Created(...)、Results.Problem(...)など非 genericResultsstatic helper は使わない。[Required]IResultだけの戻り値に逃げない。[Required]response DTO を省略するためにIResultを使わない。
優先:
csharp
async Task<Results<
Created<CustomerSignupResponse>,
ProblemHttpResult>>避ける:
csharp
async Task<IResult>OpenAPI
[Contextual].Produces<T>()はOpenAPI補足が必要な場合にのみ使い、typed resultの代替にしない。[Recommended]ProblemHttpResultのstatus codeが実行時に決まるendpointでは、公開し得るstatusごとに.ProducesProblem(statusCode)を補足する。[Required]Problem DetailsのOpenAPI media typeをapplication/problem+jsonとして公開し、独自error DTO schemaへ戻さない。[Required]Swagger に公開される DTO 型名は API 利用者から見て意味が分かる名前にする。
API DTO
[Required]Request / Response DTO は HTTP 境界専用のrecordにする。[Required]DTO はFeatures/{Area}/{UseCase}/に置く。[Required]DTOはdomain entityや永続化modelと兼用しない。[Required]Response DTOはHandlerのapplication resultと兼用しない。Endpointで{Area}{UseCase}Resultから{Area}{UseCase}Responseへmappingする。[Required]DTO は同じ JSON shape でも use case ごとに定義する。shape 共有だけを理由にFeatures/{Area}/{SharedUseCaseName}やFeatures/{Area}/Dtosのような directory を作らない。[Required]複数 use case で同じ response field を返す場合も、Swagger schema と生成 client の意味を優先し、{Area}{UseCase}Responseをそれぞれ持つ。[Required]request DTO に domain method を持たせない。[Required]response DTO に domain entity をそのまま露出しない。[Required]API に出す値は primitive、string、Guid、UTCDateTimeなど OpenAPI と相性のよい型に変換する。[Required]Value Object は response 境界で.Valueなどに展開する。[Contextual]nullable は API として null が意味を持つ場合だけ使う。[Contextual]Request DTO は 5 項目以上、または同型 property が 3 つ以上ある場合は property record にする。[Contextual]小さい Request DTO と少数項目の Response DTO は positional record を使ってよい。[Recommended]Response DTO は項目が多い、nullable が多い、同型 property が多い場合は property record を推奨する。[Required]Swaggerに出るRequest / Response DTO名にはareaとuse case名を含める。
csharp
public record CustomerSignupRequest
{
public required string Email { get; init; }
public required string LastName { get; init; }
public required string FirstName { get; init; }
}
public record CustomerSignupResponse(
string CustomerDisplayId,
Guid ObjectId,
string Email);禁止:
csharp
public record Request(string Email);
public record Response(string CustomerDisplayId);
public record SignupRequest(string Email);
public record SignupResponse(string CustomerDisplayId);[Required]API DTO の日時は UTCDateTimeに統一し、JSON では2026-05-18T12:34:56Zのような Z 付き ISO 8601 として扱う。API request で日時を受ける場合はDateTime.Kind == DateTimeKind.Utcを validation する。タイムゾーンなし入力を拒否する必要がある endpoint は JSON converter / model binder で補強する。