1. HOME
  2. ブログ
  3. エンジニアリング
  4. Route HandlersでAPIを設計して呼び出してみよう

BLOG

ブログ

エンジニアリング

Route HandlersでAPIを設計して呼び出してみよう

はじめに

本章では、Next.jsのRoute Handlersについて解説します。

ナビゲーション右上のユーザ情報部分を開発しながら学んでいきます。

チュートリアルの全体像

本チュートリアルを通じて学べる内容は以下のようになります。

  1. Next.jsの開発環境をセットアップ
  2. 画面デザインしながら基礎を学ぼう
  3. App Routerを理解して使ってみよう
  4. Next.js+Postgres+PrismaでDB設計
  5. サーバコンポーネントでデータ取得
  6. サーバアクションでデータ変更
  7. Vercel Blobで画像アップロード実装
  8. Suspenseでローディングをリッチに
  9. Zodを使ってバリデーション実装
  10. useActionStateでローディング実装
  11. Auth.js v5で認証機能導入
  12. 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の定義と呼び出し方法について解説しました。

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

関連記事