next.jsは、reactと違ってapiサーバも作れるらしいので、とりあえずhello,world! → DB接続(prisma) → CRUD APIサーバ → フロントエンドから操作できるようにしてみた。
npx create-next-app hello-world-next
next.jsで開発するなら、typescript, ESLint, Tailwind.cssは?
って聞いてくるけど、全部NOで!
hello-world-next/app/page.js
1 2 3 |
export default function Home() { return <h1>Hello, World!</h1>; } |
npm run dev
http://localhost:3000/ でブラウザ上で hello,world!が表示される。
APIサーバも簡単。 http://localhost:3000/api/hello
hello-world-next/app/api/hello/route.js
1 2 3 4 5 |
export async function GET(request) { return new Response(JSON.stringify({ message: 'Hello, World!' }), { headers: { 'Content-Type': 'application/json' }, }); } |
DB接続を試してみる。PrismaというORマッパーを使うらしい。
1 2 3 |
npm install @prisma/client npm install -D prisma npx prisma init |
hello-world-next/prisma/schema.prismaがDB接続設定ファイル。
ローカルのxamppのMariaDBに接続して、DBとテーブルを作る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
datasource db { provider = "mysql" url = "mysql://root:@localhost:3306/mydatabase" } generator client { provider = "prisma-client-js" } model User { id Int @id @default(autoincrement()) name String email String @unique } |
以下のコマンドでマイグレーションされ
mydatabaseというDBインスタンス内にuserテーブルが生成される
1 |
npx prisma migrate dev --name init |
npm run dev してから http://localhost:3000/api/users で、crudできるrestful apiサーバを実装してみる。
hello-world-next/app/api/users/route.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); export async function GET(request) { const users = await prisma.user.findMany(); return new Response(JSON.stringify(users), { headers: { 'Content-Type': 'application/json' }, }); } export async function POST(request) { const data = await request.json(); const user = await prisma.user.create({ data: { name: data.name, email: data.email, }, }); return new Response(JSON.stringify(user), { headers: { 'Content-Type': 'application/json' }, }); } export async function PUT(request) { const data = await request.json(); const user = await prisma.user.update({ where: { id: data.id }, data: { name: data.name, email: data.email, }, }); return new Response(JSON.stringify(user), { headers: { 'Content-Type': 'application/json' }, }); } export async function DELETE(request) { const data = await request.json(); const user = await prisma.user.delete({ where: { id: data.id }, }); return new Response(JSON.stringify(user), { headers: { 'Content-Type': 'application/json' }, }); } |
postmanで試してみたら、ちゃんと出来た!
GET /api/users:
ユーザー一覧を取得します。
POST /api/users:
新規ユーザーを作成します。
リクエストボディ: {“name”: “Alice”, “email”: “alice@example.com”}
PUT /api/users:
ユーザー情報を更新します。
リクエストボディ: {“id”: 1, “name”: “Alice Updated”, “email”: “alice.updated@example.com”}
DELETE /api/users:
ユーザーを削除します。
リクエストボディ: {“id”: 1}
ブラウザから操作できるように、フロントエンドも生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
'use client'; // このコンポーネントはクライアント側で実行されることを示す import { useState, useEffect } from 'react'; // useStateとuseEffectをインポート export default function UsersPage() { // ユーザーの状態と、新規および編集用の名前とメールアドレスの状態を定義 const [users, setUsers] = useState([]); // ユーザーの一覧を保持 const [newName, setNewName] = useState(''); // 新規ユーザーの名前 const [newEmail, setNewEmail] = useState(''); // 新規ユーザーのメールアドレス const [editId, setEditId] = useState(null); // 編集中のユーザーのID const [editName, setEditName] = useState(''); // 編集中のユーザーの名前 const [editEmail, setEditEmail] = useState(''); // 編集中のユーザーのメールアドレス // useEffectを使ってコンポーネントの初期レンダリング時にユーザー一覧を取得 useEffect(() => { async function fetchUsers() { const response = await fetch('/api/users'); // APIエンドポイントにリクエスト const data = await response.json(); // レスポンスをJSON形式で取得 setUsers(data); // ユーザー一覧を状態に設定 } fetchUsers(); }, []); // 空の依存配列で最初の一回だけ実行 // 新規ユーザーを追加する関数 async function addUser() { const response = await fetch('/api/users', { method: 'POST', // POSTリクエストを送信 headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newName, email: newEmail }), // 新規ユーザーのデータを送信 }); const newUser = await response.json(); // レスポンスを新規ユーザーとして取得 setUsers([...users, newUser]); // ユーザー一覧を更新 setNewName(''); // 入力フィールドをクリア setNewEmail(''); // 入力フィールドをクリア } // ユーザーを更新する関数 async function updateUser() { const response = await fetch('/api/users', { method: 'PUT', // PUTリクエストを送信 headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: editId, name: editName, email: editEmail }), // 更新データを送信 }); const updatedUser = await response.json(); // レスポンスを更新されたユーザーとして取得 setUsers(users.map(user => (user.id === editId ? updatedUser : user))); // ユーザー一覧を更新 setEditId(null); // 編集状態を解除 setEditName(''); // 入力フィールドをクリア setEditEmail(''); // 入りフィールドをクリア } // ユーザーを削除する関数 async function deleteUser(id) { await fetch('/api/users', { method: 'DELETE', // DELETEリクエストを送信 headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id }), // 削除するユーザーのIDを送信 }); setUsers(users.filter(user => user.id !== id)); // ユーザー一覧から削除 } // ユーザーの編集を開始する関数 function startEditing(user) { setEditId(user.id); // 編集するユーザーのIDを設定 setEditName(user.name); // 編集するユーザーの名前を設定 setEditEmail(user.email); // 編集するユーザーのメールアドレスを設定 } return ( <div> <h1>User List</h1> <ul> {users.map(user => ( <li key={user.id}> {user.id === editId ? ( <> {/* 名前の入力フィールド */} <input type="text" value={editName} onChange={e => setEditName(e.target.value)} /> {/* メールアドレスの入力フィールド */} <input type="email" value={editEmail} onChange={e => setEditEmail(e.target.value)} /> <button onClick={updateUser}>Save</button> <button onClick={() => setEditId(null)}>Cancel</button> </> ) : ( <> {user.name} ({user.email}){' '} <button onClick={() => startEditing(user)}>Edit</button> <button onClick={() => deleteUser(user.id)}>Delete</button> </> )} </li> ))} </ul> {/* 新規ユーザーの名前の入力フィールド */} <input type="text" placeholder="Name" value={newName} onChange={e => setNewName(e.target.value)} /> {/* 新規ユーザーのメールアドレスの入力フィールド */} <input type="email" placeholder="Email" value={newEmail} onChange={e => setNewEmail(e.target.value)} /> <button onClick={addUser}>Add User</button> {/* 新規ユーザー追加ボタン */} </div> ); } |
laravelはバックエンドから、next.jsはフロントエンドから
結局どっちもフルスタックフレームワークになっているから、収斂進化みたいだな