Skip to Content

Next.jsでAPIを作ろう

このページで学ぶこと

  • Next.js の Route Handlers で API エンドポイントを作れる
  • GET・POST リクエストを処理できる
  • フロントエンドから自分で作った API を呼び出せる

Route Handlers とは

Next.js の App Router では、app/api/ フォルダに route.js を置くことで API を作れます。

app/
├── api/
│   └── todos/
│       └── route.js    → GET /api/todos, POST /api/todos
└── page.js
plaintext

やってみよう

ステップ1: GET エンドポイントを作る

app/api/todos/route.js を作成する。

// app/api/todos/route.js
import { NextResponse } from 'next/server'
 
// ダミーデータ(後でDBに置き換える)
const todos = [
  { id: 1, title: '牛乳を買う', completed: false },
  { id: 2, title: '洗濯する', completed: true },
  { id: 3, title: '課題を終わらせる', completed: false },
]
 
// GET /api/todos
export async function GET() {
  return NextResponse.json(todos)
}
javascript

ブラウザで http://localhost:3000/api/todos にアクセスすると、JSONが表示されます。


ステップ2: POST エンドポイントを追加する

// app/api/todos/route.js
import { NextResponse } from 'next/server'
 
let todos = [
  { id: 1, title: '牛乳を買う', completed: false },
  { id: 2, title: '洗濯する', completed: true },
]
 
// GET /api/todos
export async function GET() {
  return NextResponse.json(todos)
}
 
// POST /api/todos
export async function POST(request) {
  // リクエストボディをJSONとして読み込む
  const body = await request.json()
 
  // 簡単なバリデーション
  if (!body.title) {
    return NextResponse.json(
      { error: 'titleは必須です' },
      { status: 400 }  // Bad Request
    )
  }
 
  // 新しいTodoを作成
  const newTodo = {
    id: todos.length + 1,
    title: body.title,
    completed: false,
  }
  todos.push(newTodo)
 
  return NextResponse.json(newTodo, { status: 201 })  // Created
}
javascript

ステップ3: 特定IDのエンドポイントを作る

app/api/todos/[id]/route.js を作成する。

// app/api/todos/[id]/route.js
import { NextResponse } from 'next/server'
 
let todos = [
  { id: 1, title: '牛乳を買う', completed: false },
  { id: 2, title: '洗濯する', completed: true },
]
 
// GET /api/todos/:id
export async function GET(request, { params }) {
  const id = parseInt(params.id)
  const todo = todos.find((t) => t.id === id)
 
  if (!todo) {
    return NextResponse.json({ error: '見つかりません' }, { status: 404 })
  }
 
  return NextResponse.json(todo)
}
 
// DELETE /api/todos/:id
export async function DELETE(request, { params }) {
  const id = parseInt(params.id)
  todos = todos.filter((t) => t.id !== id)
 
  return NextResponse.json({ message: '削除しました' })
}
javascript

ステップ4: フロントエンドから呼び出す

app/page.js を書き換えて、自分で作った API を呼び出してみましょう。

// app/page.js
'use client'
import { useState, useEffect } from 'react'
 
export default function TodoApp() {
  const [todos, setTodos] = useState([])
  const [input, setInput] = useState('')
 
  // 初回表示時にTodo一覧を取得
  useEffect(() => {
    fetch('/api/todos')
      .then((res) => res.json())
      .then((data) => setTodos(data))
  }, [])
 
  // Todoを追加する
  const addTodo = async () => {
    const res = await fetch('/api/todos', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title: input }),
    })
    const newTodo = await res.json()
    setTodos([...todos, newTodo])
    setInput('')
  }
 
  return (
    <div style={{ padding: '32px' }}>
      <h1>Todoアプリ</h1>
      <div>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="新しいTodoを入力"
        />
        <button onClick={addTodo}>追加</button>
      </div>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  )
}
javascript

確認しよう

  • GET /api/todos でJSONが返ってくることをブラウザで確認した
  • POST /api/todos でTodoを追加できた
  • フロントエンドから fetch でAPIを呼び出せた
  • 400・404 のエラーレスポンスを返せた

AIに聞いてみよう

「Next.jsのRoute Handlersでミドルウェアを使って認証チェックをするにはどうしますか?」


次のステップ

DBスキーマを設計しよう

Last updated on