APIの役割

DDDでのAPIの役割

DDDのレイヤー構成では、APIはPresentation層に含まれます。Presentation層は、利用者や外部システムから要求を受け取り、Application Serviceを呼び出し、その結果を外部へ返します。

APIはHTTPリクエストとレスポンスを扱います。参加できるかどうかなどの業務上の判断は、Application Serviceを通してドメインモデルへ任せます。

具体例で整理する

例えば、フットサルNOWで参加者が募集の「参加する」を押すと、参加申請APIへリクエストが送られます。

APIは、リクエストから「募集ID」を受け取り、ログインしている利用者から「参加者ID」を取得します。その値を参加申請のApplication Serviceへ渡し、処理が完了したらHTTPレスポンスを返します。

  1. 1リクエストから募集IDを受け取る
  2. 2ログイン中の利用者から参加者IDを取得する
  3. 3参加申請のApplication Serviceを呼ぶ
  4. 4処理結果をHTTPレスポンスとして返す

コードで表す

Next.jsのRoute Handlerから、参加申請のApplication Serviceを呼び出す例です。

// src/app/api/recruitments/[recruitmentId]/participation/route.ts

export async function POST(
  _request: Request,
  context: { params: Promise<{ recruitmentId: string }> },
) {
  // URLから募集IDを受け取る
  const { recruitmentId } = await context.params;

  // ログインしている利用者を取得する
  const signedInUser = await requireSignedInUser();

  // HTTPの入力から、参加申請のCommandを作る
  const command: RequestParticipationCommand = {
    recruitmentId,
    participantId: signedInUser.id,
    requestedAt: new Date(),
  };

  // 参加申請のApplication ServiceへCommandを渡す
  await requestParticipationApplicationService.execute(command);

  // 参加申請が完了したことをHTTPレスポンスで返す
  return new Response(null, { status: 204 });
}

このAPIは、参加申請に必要な値を用意し、IRequestParticipationApplicationServiceで決めた方法でApplication Serviceを呼びます。

APIに業務ルールを書かない

「申込期限を過ぎていないか」「同じ人が二重に申請していないか」「定員に達していないか」は、APIでは確認しません。これらは参加申請の業務ルールなので、募集のドメインモデルが確認します。

一方で、募集IDが文字列として渡されているかなど、リクエストとして受け取れる形式かを確認する処理はAPIに置けます。

ディレクトリで表す

src/
├── app/
│   └── api/
│       └── recruitments/
│           └── [recruitmentId]/
│               └── participation/
│                   └── route.ts  ← Presentation層(API)
└── features/
    └── futsal/
        ├── application/
        │   ├── IRequestParticipationApplicationService.ts
        │   └── RequestParticipationApplicationService.ts
        └── domain/
            └── recruitment/
                └── RecruitmentEntity.ts

※ APIの配置はフレームワークによって異なります。この例では、Next.jsのRoute HandlerをPresentation層として扱っています。