0. はじめに
学んだ技術や知識についてを備忘録としてまとめることを目的にしている。
0.1. 開発環境
- OS: macOS Sequoia 15.5
- エディタ: VS Code
- ライブラリ: React 19.2.0
- フレームワーク: Next.js 16.0.5
- ルーター: App Router
プロジェクト作成方法
ターミナルにてプロジェクトを作成したいディレクトリ内に移動して、以下のコマンドを実行。
# プロジェクトの雛形を作成
npx create-next-app
プロジェクト作成時の質問は以下の通り。
作成が完了したら以下のコマンドで起動
npm run dev
1. 基本知識
1.1. APIとは
Application Programming Interfaceの略。システムの実装を隠蔽し、機能と利用手順のみを外部に公開するインターフェースである。
1.1.1. Web API
HTTP/HTTPSプロトコルを用いて、ネットワークを経由してプログラム間でデータのやり取りや機能の呼び出しを行うインターフェース。プログラムがローカル環境ではなくURI(Uniform Resource Identifier)で特定されるエンドポイントに対してリクエストを送り、メソッド(GET, POST, PUT, DELETEなど)によって操作を定義する。本記事で使うAPIとは主に「Web API」を指すこととする。
1.1.2. OS API
オペレーティングシステムAPI。アプリケーションがハードウェア資源(CPU、メモリ、ディスク、ネットワークなど)を安全に利用するためにOSが提供するインターフェース。ハードウェアの直接操作を抽象化・保護し、プログラムがOSの種類に依存せずリソースを使えるようにする。
例:
- Windows API: Windows OSの昨日(ウィンドウ操作、ファイル管理、システム情報取得など)をC言語やC++などのプログラムから利用できるように提供されたAPI
1.1.3. ライブラリ API
プログラムの特定の機能を実行するために、外部から呼び出せる関数、クラス、メソッドの集合(インターフェース)。
1.1.4. フレームワーク API
特定のソフトウェアフレームワークが持つ「制御の反転」構造を維持しつつ、開発者がそのフレームワークの機能にアクセスし、自身のコードをシステムに組み込むために提供される公開インターフェースの集合。
例:
- Android Framework API: OSというフレームワーク上でアプリを動かすためのAPI
1.1.5. ハードウェア API
ソフトウェアがハードウェア(GPUやオーディオチップなど)の機能を直接、またはドライバーを介して制御するためのインターフェース。
例:
- CUDAやOpenCL
1.1.6. ABI
application。ソースコードレベルではなくバイナリレベルでのインターフェース。
1.1.7. 通信プロトコル API※Web API以外のリモートAPI
ネットワークを介するものの、Web標準(HTTP/JSON)とは異なるプロトコルや方式を用いたもの。
例:
- RPC: Remote Procedure Call。ネットワーク上の別サーバーにある関数をあたかもローカルの関数であるかのように呼び出すAPI
1.2. Mock APIとは
開発時において、本来想定しているWeb APIが完成されていない、あるいは利用できない状況下で使用する仮のWeb APIのこと。
1.3. Route Handlerとは
Next.jsにおいて、アプリケーション内に独自のAPIエンドポイントを作成する仕組み。Web標準のFetch APIに準拠している。Next.jsのRoute Handlerは、appディレクトリ内の構造に従い、APIエンドポイントとして機能させるには、route.tsというファイル名を使用する。例えば、エンドポイントが/userであった場合、/app/user/route.tsとなるようにroute.tsファイルを作成すればよい。ただし、本記事では便宜上Mock APIは/app/apiディレクトリ内にまとめることとする。
2. Mock API作成
2.1. GETメソッド
API仕様が以下であるとし、これに対するMock APIを作成する。
-
エンドポイント: GET /search
-
パスパラメータ
パラメータ 型 必須 説明 q string 任意 ユーザー名の部分一致検索キーワード
レスポンス例:
[
{ "id": 1, "name": "A" },
{ "id": 2, "name": "B" }
]
2.1.1. Route Handlerの作成
以下のディレクトリ構成でroute.tsを作成する。
src
└─ app
└─ api
└─ search
└─ route.ts ← 作成
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
// URLから探索クエリを取得
const searchParam = request.nextUrl.searchParams;
const query = searchParam.get('q');
// モックデータ
const mockData = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Ben" },
{ id: 3, name: "Cecil" },
{ id: 4, name: "Dominic" }
];
const filteredData = query
? mockData.filter(obj => obj.name.includes(query))
: mockData;
// レスポンスを返す
return NextResponse.json(filteredData);
}
2.1.2. 型の定義
以下のディレクトリ構成で型定義ファイルを作成する。
src
└─ app
├─ api
└─ types
└─ user.ts ← 作成
export interface UserResponse {
id: number;
name: string;
}
2.1.3. fetch関数の作成
'use client';
import { useState } from 'react';
import { UserResponse } from "./types/user";
export default function Home() {
// APIで取得したデータを管理
const [results, setResults] = useState([]);
const [error, setError] = useState<string | null>(null);
const baseUrl = 'http://localhost:3000'
const token = "dummy_token"
// GET /search
const handleSearch = async (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value;
// 入力が空の場合はリセットして終了
if (!query) {
setResults([]);
setError(null);
return;
}
const url = `${baseUrl}/api/search?q=${query}`;
try {
// APIデータを取得
const response = await fetch(url, {
method: "GET",
headers: {
// 認証用トークン
'Authorization': `Bearer ${token}`,
// JSON形式でデータを受け取りたいことを明示
'Accept': 'application/json',
}
});
if (!response.ok) {
throw new Error(`エラーが発生しました(Status: ${response.status})`);
}
// JSON形式のデータを取得
const data = await response.json();
setResults(data);
} catch (err) {
// ネットワークエラーや上記のエラーをキャッチ
setError(err instanceof Error ? err.message : "予期せぬエラーが発生しました");
setResults([]); // リストをクリア
}
}
return (
<div>
<main>
<input
type="text"
onChange={handleSearch}
placeholder="名前で検索..."
className="border p-2"
/>
{error && <p className="text-red-500">{error}</p>}
{!error && results.length === 0 && (
<p className="text-gray-400">該当するユーザーはいません</p>
)}
<ul>
{results.map((user: UserResponse) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</main>
</div>
);
}
Acceptヘッダー
GETリクエストでは、リクエストを送る側がサーバーからのレスポンスをどのような形式(JSON, XMLなど)で受け取りたいかをサーバーに伝えるために、Acceptヘッダーを使用する。2.1.4. 実行結果
2.2. POSTメソッド
API仕様が以下であるとし、これに対するMock APIを作成する。
-
エンドポイント: POST /users
-
リクエストボディ
パラメータ 型 必須 説明 name string 必須 ユーザー氏名 email string 必須 ユーザーのメールアドレス
レスポンス例:
{
"id": "452",
"name": "山田 太郎",
"email": "yamada@example.com",
"createdAt": "2024-05-20T10:00:00.000Z"
}
{ "error": "Name and Email are required" }
2.2.1. Route Handlerの作成
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
// リクエストボディの解析
const body = await request.json();
const { userName, email } = body;
if (!userName || !email) {
return NextResponse.json(
{ error: "Name and Email are required" },
{ status: 400 }
);
}
const newMockData = {
id: Math.floor(Math.random() * 1000).toString(),
userName,
email,
createdAt: new Date().toISOString(),
};
return NextResponse.json(newMockData, { status: 201 });
}
2.2.2. 型の定義
export interface UserRequest {
userName: string;
email: string;
}
2.2.3. fetch関数の作成
'use client';
import Dropdown from "@/components/Dropdown";
import { useState } from 'react';
import { UserRequest } from "./types/user";
export default function Home() {
// APIで取得したデータを管理
const [error, setError] = useState<string | null>(null);
const [userName, setUserName] = useState("")
const [email, setEmail] = useState("")
const baseUrl = 'http://localhost:3000'
// POST /users
const handleSubmit = async (e: React.FormEvent) => {
// デフォルトのイベント動作をキャンセル
e.preventDefault();
const url = `${baseUrl}/api/users`;
const requestBody: UserRequest = { userName, email };
try {
const response = await fetch(url,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "登録に失敗しました");
}
// リクエスト後にリセット
setUserName("");
setEmail("");
} catch (err) {
// ネットワークエラーや上記のエラーをキャッチ
setError(err instanceof Error ? err.message : "予期せぬエラーが発生しました");
}
}
return (
<div>
<main>
<div>
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
<input
type="text"
placeholder="名前"
value={userName}
onChange={(e) => setUserName(e.target.value)}
className="border p-2"
/>
<input
type="email"
placeholder="メールアドレス"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="border p-2"
/>
<button type="submit" className="bg-blue-500 text-white p-2 rounded">
ユーザー登録
</button>
</form>
</div>
</main>
</div>
);
}
Content-Typeヘッダー
Content-Typeヘッダーは、リクエストボディ(body)が含まれている場合に、そのボディ内のデータがどのような形式(メディアタイプ)であるかをサーバーに伝えるために使用する。
よって、主にPOST/PUT/PATCHに使用する。
GETメソッドにおいては、サーバーからデータを取得することを目的としており、通常リクエストボディを持たない。よって、ボディの内容形式を示すContent-Typeは不要となる。データ取得の条件(フィルタリングなど)は、URLのクエリパラメータとして送信される。
2.2.4. 実行結果
POSTリクエストが正しく送られているか確認するには、ブラウザのデベロッパーツールのネットワークタブを開き、送信されたリクエストのペイロードとレスポンスを確認する。
2.3. PUTメソッド
API仕様が以下であるとし、これに対するMock APIを作成する。
-
エンドポイント: PUT /users/[id]
-
パスパラメータ
パラメータ 型 説明 id string 更新したいユーザーのID -
リクエストボディ
パラメータ 型 必須 説明 name string 任意 新しい氏名 email string 任意 新しいメールアドレス
レスポンス例:
{
"id": "452",
"name": "山田 太郎",
"email": "yamada@example.com",
"createdAt": "2024-05-20T10:00:00.000Z"
}
2.3.1. Route Handlerの作成
import { UserRequest } from "@/app/types/user";
import { NextResponse } from "next/server";
export async function PUT(
request: Request,
{ params }: { params: { id: string } }
) {
// 更新対象のID
const id = params.id;
const body = await request.json();
const { userName, email }: UserRequest = body;
// 更新後のデータを想定してレスポンスを作成
const MockData = {
id,
name: userName || "未設定",
email: email || "未設定",
updatedAt: new Date().toISOString(),
};
return NextResponse.json(MockData, { status: 200 });
}

2.3.2. 型の定義
2.2.2.型の定義と同じ。
2.3.3. fetch関数の作成
'use client';
import { useState } from 'react';
import { UserRequest } from './types/user';
export default function HOme() {
const [targetId, setTargetId] = useState(""); // 更新対象のID
const [userName, setUserName] = useState("");
const [email, setEmail] = useState("");
const [error, setError] = useState<string | null>(null);
const baseUrl = 'http://localhost:3000'
// PUT /users/[id]
const handleUpdate = async (e: React.FormEvent) => {
e.preventDefault();
// IDが未入力の場合は中断
if (!targetId) {
setError("更新対象のIDを入力してください");
return;
}
const url = `${baseUrl}/api/users/${targetId}` // パスにIDを埋め込む
const requestBody: UserRequest = { userName, email };
try {
const response = await fetch(url,
{
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "更新に失敗しました");
}
// リクエスト後にリセット
setTargetId("");
setUserName("");
setEmail("");
} catch (err) {
setError(err instanceof Error ? err.message : "予期せぬエラーが発生しました");
}
};
return (
<div>
<form onSubmit={handleUpdate} className="flex flex-col">
{/* ID入力フィールド */}
<div>
<label>更新対象のID</label>
<input
type="text"
placeholder="例: 1"
value={targetId}
onChange={(e) => setTargetId(e.target.value)}
className="border rounded"
/>
</div>
{/* データ入力フィールド */}
<div>
<label>新しい名前</label>
<input
type="text"
placeholder="名前"
value={userName}
onChange={(e) => setUserName(e.target.value)}
className="border rounded"
/>
</div>
<div>
<label>新しいメールアドレス</label>
<input
type="email"
placeholder="メールアドレス"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="border rounded"
/>
</div>
<button type="submit" className="rounded">
情報を更新する
</button>
</form>
{/* フィードバック表示 */}
{error && <p className="text-red-500">{error}</p>}
</div>
);
}
2.3.4. 実行結果
参考資料
記事作成にあたり、以下のサイトを参考にさせて頂きました。心より感謝申し上げます。
- APIモック:「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
- APIモックを使って開発速度を上げよう
- APIがなくとも開発を進める。APIモックツールまとめ
- 実機でモックAPIを叩く
- 意外と身近にある【API】を初心者にも分かりやすく解説
- APIとは? API連携の仕組みや事例をわかりやすく紹介
- 今更聞けない(かもしれない)Win32API概要
- 今更だけど、脱Windows APIしようと思う(;´・ω・)
- ライブラリAPIとは?設計・ABI互換・バージョニング・セキュリティまでの実践ガイド
- CUDA Driver APIでカーネル作成と実行まで
- いまさら聞けないCUDA:GPU並列処理の基礎技術
- CUDAとOpenCLどっちがいいの?
- 様々な認証方式について(Bearer,Basic,Digest,Form,OAuth)
- fetch関数の備忘録
- イメージで見るReactのデータ取得、fetch方法の変遷
- 【JavaScript】 fetchでAPIに慣れるための問題集
- 【初学】初めてのAPI(fetchとかpromiseとか良くわからない)
- Fetch API 実用例
- 公式ドキュメント:fetch API
- 公式ドキュメント:Using the Fetch API






