第3部:実践チュートリアル Step 16 / 20

Todoアプリ - 連携編

いよいよ最終ステップ!フロントエンドとバックエンドを連携させて、完全なTodoアプリを完成させます。

連携の流れ

Next.js
localhost:3000
⇄ fetch API ⇄
FastAPI
localhost:8000

Step 1: API通信関数を作成

AIへの指示

frontend/src/lib/api.ts を作成して、
TodoのAPI通信関数を作成してください。

関数:
- fetchTodos(): 全Todo取得
- createTodo(title: string): Todo作成
- updateTodo(id: number, data: { completed?: boolean }): Todo更新
- deleteTodo(id: number): Todo削除

APIのベースURL: http://localhost:8000

完成コード例: src/lib/api.ts

import { Todo } from "@/types/todo";

const API_URL = "http://localhost:8000";

export async function fetchTodos(): Promise<Todo[]> {
  const res = await fetch(`${API_URL}/todos`);
  return res.json();
}

export async function createTodo(title: string): Promise<Todo> {
  const res = await fetch(`${API_URL}/todos`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ title }),
  });
  return res.json();
}

export async function updateTodo(
  id: number,
  data: { title?: string; completed?: boolean }
): Promise<Todo> {
  const res = await fetch(`${API_URL}/todos/${id}`, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  return res.json();
}

export async function deleteTodo(id: number): Promise<void> {
  await fetch(`${API_URL}/todos/${id}`, {
    method: "DELETE",
  });
}

Step 2: ページをAPI連携に変更

AIへの指示

frontend/src/app/page.tsx を編集して、
モックデータの代わりにAPIを使うように変更してください。

変更内容:
1. useEffectで初回読み込み時にfetchTodosを呼ぶ
2. addTodo関数をcreateToを使うように変更
3. toggleTodo関数をupdateTodoを使うように変更
4. deleteTodo関数をdeleteTodoAPIを使うように変更
5. ローディング状態を追加(読み込み中は「Loading...」を表示)

主要な変更点

"use client";

import { useState, useEffect } from "react";
import { Todo } from "@/types/todo";
import * as api from "@/lib/api";

export default function Home() {
  const [todos, setTodos] = useState<Todo[]>([]);
  const [newTitle, setNewTitle] = useState("");
  const [loading, setLoading] = useState(true);

  // 初回読み込み
  useEffect(() => {
    api.fetchTodos().then((data) => {
      setTodos(data);
      setLoading(false);
    });
  }, []);

  // Todo追加
  const addTodo = async () => {
    if (!newTitle.trim()) return;
    const newTodo = await api.createTodo(newTitle);
    setTodos([...todos, newTodo]);
    setNewTitle("");
  };

  // 完了切り替え
  const toggleTodo = async (id: number, completed: boolean) => {
    const updated = await api.updateTodo(id, { completed: !completed });
    setTodos(todos.map(t => t.id === id ? updated : t));
  };

  // 削除
  const handleDelete = async (id: number) => {
    await api.deleteTodo(id);
    setTodos(todos.filter(t => t.id !== id));
  };

  if (loading) return <div>Loading...</div>;

  // ... 以下、表示部分は同じ
}

Step 3: 動作確認

両方のサーバーを起動

ターミナル1(バックエンド)

cd backend
uvicorn main:app --reload

ターミナル2(フロントエンド)

cd frontend
npm run dev

確認項目

  • ページを開くとバックエンドのデータが表示される
  • 新しいTodoを追加すると、バックエンドにも保存される
  • 完了状態を切り替えると、バックエンドも更新される
  • 削除すると、バックエンドからも削除される
  • ページをリロードしてもデータが残っている!

Todoアプリ完成!

おめでとうございます!Next.js + FastAPIのフルスタックアプリが完成しました!

よくあるエラーと解決法

CORSエラー

ブラウザのコンソールに「CORS」と表示される

解決法:FastAPIのCORS設定でhttp://localhost:3000を許可しているか確認

データが表示されない

Loading...のまま、またはエラー

解決法:バックエンドサーバーが起動しているか確認。http://localhost:8000/docsにアクセスできるか確認

追加/更新/削除が反映されない

操作してもリストが変わらない

解決法:API関数でawaitを忘れていないか確認。ブラウザのコンソールでエラーを確認

第3部完了!

チュートリアルお疲れさまでした!Next.js + FastAPIでフルスタックアプリを作る流れを体験できました。

前へ:フロントエンド編 次へ:よくあるエラー集