Route HandlersでAPIを設計して呼び出してみよう
はじめに
本章では、Next.jsのRoute Handlersについて解説します。
ナビゲーション右上のユーザ情報部分を開発しながら学んでいきます。
チュートリアルの全体像
本チュートリアルを通じて学べる内容は以下のようになります。
- Next.jsの開発環境をセットアップ
- 画面デザインしながら基礎を学ぼう
- App Routerを理解して使ってみよう
- Next.js+Postgres+PrismaでDB設計
- サーバコンポーネントでデータ取得
- サーバアクションでデータ変更
- Vercel Blobで画像アップロード実装
- Suspenseでローディングをリッチに
- Zodを使ってバリデーション実装
- useActionStateでローディング実装
- Auth.js v5で認証機能導入
- Route HandlersでAPIを設計
動画で学びたい方はこちらから!
Route Handlers概要
Route Handlersという機能を使うと、APIを構築することができます。
Route Handlersの定義方法
Route Handlersを定義するには、route.tsというファイルを作成します。
さっそく定義しましょう。
app/api/route.ts
を作成して以下のように記述します。
export async function GET(request: Request) {
return new NextResponse("hello world!");
}
localhost:3000/apiにアクセスしてみてください。
hello world!と表示されます。
また、JSONを返すこともできます。
先ほどのコードを以下のように変更しましょう。
app/api/route.ts
import { NextResponse } from "next/server";
export async function GET() {
const data = {
title: "hello world!",
};
return NextResponse.json(data);
}
localhost:3000/api
にアクセスしてみましょう。
今度は、以下のように表示されます。
{"title":"hello world!"}
route.tsで定義する関数名は、HTTPリクエストのメソッド名にそろえます。
export async function GET() {}
export async function POST() {}
export async function PUT() {}
export async function DELETE() {}
実践
まずは、APIルート定義を行います。
app/api/me.route.ts
import { fetchMe } from "@/lib/apis";
export async function GET() {
const me = await fetchMe();
return Response.json(me);
}
components/layouts/navigation-menu.tsx
"use client";
import { logout } from "@/lib/actions";
import clsx from "clsx";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
type User = {
name: string;
image: string | null;
};
export default function NavigationMenu() {
const [showMenu, setShowMenu] = useState(false);
const passname = usePathname();
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetch("/api/me")
.then((res) => res.json())
.then((me) => setUser(me));
}, [passname]);
return (
<div className="relative inline-block sm:ms-6 sm:items-center">
<button
id="menu-button"
className="my-6 inline-flex items-center rounded-md border border-transparent bg-white px-3 text-sm font-medium leading-4 text-gray-500 transition duration-150 ease-in-out hover:text-gray-700 focus:outline-none"
onClick={() => setShowMenu(true)}
>
{user?.image && (
<Image
className="mr-2 block aspect-square size-6 rounded-full object-cover"
src={user.image}
width={64}
height={64}
alt="user logo"
/>
)}
<div>{user?.name}</div>
<div className="ms-1">
<svg
className="size-4 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</div>
</button>
<div
className={clsx(
"absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none",
{ block: showMenu, hidden: !showMenu },
)}
onClick={() => setShowMenu(false)}
>
<div className="py-1">
<Link
href="/dashboard"
className="block px-4 py-2 text-sm text-gray-700"
>
ダッシュボード
</Link>
</div>
<div className="py-1">
<Link
href="/profile"
className="block px-4 py-2 text-sm text-gray-700"
>
プロフィール
</Link>
</div>
<div className="py-1">
<Link
href="/posts/create"
className="block px-4 py-2 text-sm text-gray-700"
>
投稿作成
</Link>
</div>
<div className="py-1">
<Link href="/posts" className="block px-4 py-2 text-sm text-gray-700">
新着投稿
</Link>
</div>
<div className="py-1">
<Link href="/users" className="block px-4 py-2 text-sm text-gray-700">
オーナー
</Link>
</div>
<div className="py-1">
<form action={logout}>
<button
type="submit"
className="block px-4 py-2 text-sm text-gray-700"
>
ログアウト 🐾
</button>
</form>
</div>
</div>
{showMenu && (
<div
className="fixed left-0 top-0 h-screen w-screen"
onClick={() => setShowMenu(false)}
/>
)}
</div>
);
}
プロフィールアイコンを変更してナビゲーションアイコンが切り替わるのを確認してみましょう。
まとめ
以上、Route Handlersの定義と呼び出し方法について解説しました。
この記事へのコメントはありません。