将来ちゃんとしたAPIのエンドポイントを作るか迷っていたため、RSCにてDBクエリを書く方法で行くか迷っていたためNext.js API routesに書いていたんですがtypeのinferしてくれなくて使いづらいかった。

まずはこんな感じで api routes

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params;

    const spot = await db.query.napSpots.findFirst({
      where: eq(napSpots.id, id),
      with: {
        ratings: {
          with: {
            user: true,
          },
        },
      },
    });

    if (!spot) {
      console.error("[API] Nap spot not found for ID:", id);
      return NextResponse.json(
        { error: "Nap spot not found" },
        { status: 404 }
      );
    }

    return NextResponse.json({
      ...spot,
    });
  } catch (error) {
    console.error("[API] Error fetching nap spot:", error);
    return NextResponse.json(
      { error: "Failed to fetch nap spot" },
      { status: 500 }
    );
  }
}

これは実際にResponseのタイプをinferしてくれますがすぐクエリの関数をクリックしてそれに飛べないしタイプを表示してくれないのでかなり使いづらいです。 ReturnType使用していく以下のように複雑になるしで

type Data = ReturnType<typeof GET> extends NextResponse<infer T> ? T : never;

zodを使用うすればいいのかとは思いましいた。

今回はRSC内にてdbクエリを書くと

export async function getNapSpotDetails(napSpotId: string) {
  const spot = await db.query.napSpots.findFirst({
    where: eq(napSpots.id, napSpotId),
    with: {
      ratings: {
        with: {
          user: true,
        },
      },
    },
  });

  if (!spot) {
    return { napSpot: null, averageRatings: null };
  }
    return {
    napSpot: spot,
    averageRatings,
  };

こちらは関数を呼び出してデータを渡す際にすぐにタイプを表示してくれて助かります。

結論としてはtRPCとreact-queryを使用して書いていたら良かったの思ったところもありましたがアプリが小さいときはRSC内にて書いたほうが開発体験もよく好きだと感じました。