Image by AGNIESZKA WEN from Pixabay
目次
・フロントエンド:Next.js(TypeScript)
・バックエンド:PHP(Laravel)
を使って、簡単な掲示板をつくります。
最低限CRUDができる機能のみの実装で、
デザインは一切せず、とにかくシンプルにしています。
以下が完成イメージです。
OS:Windows11 Home
WSL2(Ubuntu 20.04.6)
PHP:8.4.7
Laravel:12.10.2
Node:22.15.0
npm:10.9.2
Next:15.3.1
ディレクトリの構成は以下の様にします。
myapp:親ディレクトリ
├─backend:Laravelのプロジェクト
└─frontend:Nextのプロジェクト
任意の場所に「myapp」ディレクトリを作成してください。
myappディレクトリにcdコマンドで移動して、以下コマンドを実行します。
npx create-next-app frontend --typescript
コマンド実行時に質問されるのですが、今回は全てデフォルトで設定します。
Would you like to use ESLint? … No / Yes ⇒Yes
Would you like to use Tailwind CSS? … No / Yes ⇒No
Would you like your code inside a src/ directory? … No / Yes ⇒Yes
Would you like to use App Router? (recommended) … No / Yes ⇒Yes
Would you like to use Turbopack for next dev ? … No / Yes ⇒No
Would you like to customize the import alias (@/* by default)? … No / Yes ⇒No
myappディレクトリにcdコマンドで移動して、以下コマンドを実行します。
composer create-project --prefer-dist laravel/laravel backend
次に、Laravelの設定をします。
myapp/backend/.envに以下の通り1行追記します。
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:eLWHYmxf1vsK6uKmajF5SFQ4w1HsBNOmZdrEZo4bZ1c=
APP_DEBUG=true
APP_URL=http://localhost
APP_FRONTEND_URL=http://localhost:3000 #追記
~~省略~~
myapp/backend/config/app.phpに以下の通り1行追記します。
~~省略~~
'url' => env('APP_URL', 'http://localhost'),
'frontend_url' => env('APP_FRONTEND_URL', 'http://localhost'), //追記
~~省略~~
1.以下のコマンドでcors.phpを作成する
/myapp/backendにcdコマンドで移動して、以下コマンドを実行してください。
php artisan config:publish cors
2./myapp/backend/config/cors.phpを以下の様に編集します。
~~省略~~
'paths' => ['api/*', 'sanctum/csrf-cookie'],
//許可するメソッド(GET、POSTなど)
'allowed_methods' => ['*'],
//APIの使用を許可する接続元
'allowed_origins' => [config('app.frontend_url')], //変更
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true, //trueに変更
~~省略~~
1.api.phpを作成する
/myapp/backendにcdコマンドで移動して、以下コマンドを実行してください。
php artisan install:api
2./myapp/backend/routes/api.phpに以下3行を追記してください。
~~省略~~
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
//以下を追記
Route::get('/sample', function(){
// APIの戻り値はJSON型が基本
return response()->json([
'text' => 'サンプルデータ'
]);
});
3.動作確認
cdコマンドで/myapp/backendに移動し、以下コマンドを実行してWebサーバーを起動してください。
php artisan serve
ブラウザで「http://localhost:8000/api/sample」にアクセスし、
画面左上に以下のように表示されていればOKです。
{"text":"\u30b5\u30f3\u30d7\u30eb\u30c7\u30fc\u30bf"}
エスケープされているので、何が書いてあるのかよくわかりませんが、
{”text”: ~~}
の形式で表示されていれば問題ありません。
Next.js側の設定をします。
コマンドラインでcdコマンドにて/myapp/frontに移動し、
以下コマンドを実行してください。
npm install swr
swrはAjax通信処理の周辺処理を簡潔に書くための便利なパッケージです。
次にAjax通信をする関数を作成します。
myapp/frontend/src/libs/fetcher.tsとなるようフォルダ、ファイルを作成し、
fetcher.tsに以下を記述してください。
(JSXを書かないファイルの拡張子「.ts」で作成します。)
// 共通のAjax通信処理「fetcher」を作成
const fetcher = async (
// 以下はfetcherの引数
url: string, // 通信先のURL
methodVal: 'GET' | 'POST' | 'PUT' | 'DELETE', // HTTPリクエストメソッド
body?: any // POST,PUTの場合のHTTPリクエストボディの値
) => {
// BackendのURL
const BackendUrl = "http://localhost:8000";
// 通信処理
const response = await fetch(`${BackendUrl}/${url}`, {
method: methodVal, // HTTPリクエストメソッドを設定
credentials: 'include', // Cookieも含めて送る
// HTTPリクエストのヘッダー情報を設定
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest', // Ajax通信であることを伝える
},
body: body ? JSON.stringify(body) : undefined, // bodyの設定
});
// 通信エラーの場合の処理
if(!response.ok){
throw new Error("Ajax通信でエラーが発生しました。");
}
// 取得したデータをJSON形式に変換して渡す
return response.json();
}
export default fetcher;
ChatGPTに聞いてみると、
外部ライブラリの「axios」よりブラウザ標準機能のfetchが今は人気とのことで、
今回はfetchを使用しました。
myapp/frontend/src/app/page.tsxのコードを全て削除し、以下を記述します
'use client'
import styles from "./page.module.css";
import { useState } from "react";
import useSWR from "swr";
import fetcher from "@/libs/fetcher";
export default function Home(){
// Ajax通信でデータを取得(データ取得後、自動で再レンダリング)
const {data, error} = useSWR('api/sample', fetcher);
// 通信でエラー発生した時の処理
if(error) return <div>エラーが発生しました。</div>
// 「dataが無い=通信途中」の時の処理
if(!data) return <div>読み込み中</div>
return (
<div>
<h1>NextでLaravelから取得したデータ:{data.text}</h1>
</div>
)
}
LaravelとNextが通信できているかを確認します。
新規でコマンドラインを開き、
cdコマンドにて/myapp/frontendに移動して、
以下コマンドでWebサーバーを起動してください。
npm run dev
※コマンドラインは必ず新規で開いてください。
(Laravelも起動したままにする必要があります。)
ブラウザで「http://localhost:3000」にアクセスして画面左上に
と表示されていればOKです。
LaravelとNextのデータの受け渡しはできたので、掲示板機能のバックエンド側をつくっていきます。
myapp/backend/.envを以下の様に編集します。
~~省略~~
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp_db #先程作成したDBを使用する
DB_USERNAME=MySQLのユーザ名 #ご自身の環境に合わせて記入
DB_PASSWORD=MySQLのパスワード #ご自身の環境に合わせて記入
~~省略~~
myapp/backend/routes/api.phpに以下を追記してください。
use App\Http\Controllers\PostController; // Postコントローラの読み込み
~~省略~~
// 投稿の取得
//「/posts」にgetでアクセス来たらPostコントローラのIndexメソッドを実行
Route::get('/posts', [PostController::class, 'index']);
// 投稿作成
Route::post('/posts', [PostController::class, 'store']);
// 投稿の編集
Route::put('/posts/{id}', [Postcontroller::class, 'update']);
// 投稿の削除
Route::delete('/posts/{id}', [PostController::class, 'destroy']);
myapp/backendにcdコマンドで移動し、以下コマンドを実行してください。
php artisan make:model Post -mc
-m、-cオプションをつけてモデルと一緒に「マイグレーションファイル」と「コントローラ」も作成します。
以下の3ファイルが作成されます。
・app/Models/Post.php
・database/migrations/20xx_xx_xx_032058_create_posts_table.php
・app/Http/Controllers/PostController.php
Postテーブルに必要なカラムをマイグレーションファイルで定義します。
myapp/backend/database/migrations/database/migrations/20xx_xx_xx_032058_create_posts_table.php
に以下の通り1行追記します。
~~省略~~
public function up(): void
{ // ↓テーブル名
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('text')->default('入力無し'); //追記
$table->timestamps();
//$table->カラムのデータ型(カラム名)->default(デフォルト値);
});
}
~~省略~~
myapp/backendにcdコマンドで移動し、以下コマンドを実行してください。
php artisan migrate
コマンドを実行すると、
「DBもまだ作成されてないけど作りますか?」
と確認されるので、Yesで進めます。
WARN The database ‘myapp_db' does not exist on the 'mysql' connection.
Would you like to create it?()
↓こんな感じで「DONE」が表示されればOKです。
(行数は場合によって変わるので気にしないで大丈夫です。)
これで、マイグレーションファイルに記述した内容でテーブルが作成されます。
myapp/backend/app/Http/Controllers/PostController.phpを以下のように編集します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post; //Postモデルを読み込む
class PostController extends Controller
{
// 投稿を一覧表示させる画面用の処理
public function index(){
// json形式の文字列でPostテーブルの全レコードを返す
return response()->json(Post::all());
// 以下でもOK!(Laravelは配列,コレクションをreturnすると自動でjsonに変換してくれる。他メソッドも同様です。)
// return Post::all();
}
// 投稿をテーブルに登録する画面用の処理
public function store(Request $request){
// textカラム用の値だけ取得して登録(textカラム以外編集させない)
return response()->json(Post::create($request->only(['text'])));
}
public function update(Request $request, $id){
// 投稿のidで編集対象のレコードを取得
$post = Post::findOrFail($id);
// textカラムの値を書き換える
$post->text = $request->input('text');
// DBに保存
$post->save();
return response()->json($post);
}
public function destroy($id){
// 投稿のidで編集対象のレコードを取得
$post = Post::findOrFail($id);
// 投稿削除
$post->delete();
return response()->json(['message' => '投稿を削除しました']);
}
}
myapp/backend/app/Models/Post.phpを以下の様に編集してください。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// textカラム以外編集させない
protected $fillable = ['text']; //追記
}
/frontend/src/app/post/page.tsxを作成し、以下記述してください。
'use client';
import React, { useState } from 'react';
import useSWR, { mutate } from 'swr';
import fetcher from '@/libs/fetcher';
export default function PostPage() {
const [input, setInput] = useState<string>('');
// 投稿一覧を取得(GET)
const { data, error } = useSWR<any[]>('api/posts', (url:string) => fetcher(url, 'GET'));
// 投稿を作成(POST)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if(!input.trim()) return
try{
await fetcher(`api/posts`, 'POST', { text: input}) // POSTリクエスト
setInput('') // 入力欄をクリア
mutate('api/posts') // SWRキャッシュの再取得(一覧を更新)
}catch(error){
console.error('投稿エラー:', error)
}
};
// 投稿を編集(PUT)
const handleEdit = async (post: any) => {
const newText = prompt('更新後の内容を入力してください', post.text);
if(!newText) return;
try {
await fetcher(`api/posts/${post.id}`, 'PUT', { text: newText});
mutate('api/posts');
}catch(error){
console.error('更新エラー', error);
}
};
// 投稿を削除(DELETE)
const handleDelete = async(post: any) => {
if(!confirm('本当に削除しますか?')) return;
try{
await fetcher(`api/posts/${post.id}`, 'DELETE');
mutate('api/posts');
}catch(error){
console.error('削除エラー', error);
}
};
return (
<div>
<h1>掲示板</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button type="submit">投稿</button>
</form>
<ul>
{data?.map((post) => (
<li key={post.id}>
{/* 投稿の表示 */}
{post.text}:{post.created_at}
{/* 編集ボタン */}
<button onClick={() => handleEdit(post)}>編集</button>
{/* 削除ボタン */}
<button onClick={() => handleDelete(post)}>削除</button>
</li>
))}
</ul>
</div>
);
}
1)Laravelサーバーの起動: Laravelプロジェクトのルートで以下のコマンドを実行します。
php artisan serve
2)Next.jsアプリケーションの起動: Next.jsプロジェクトのルートで以下のコマンドを実行します。
npm run dev
3)ブラウザで「localhost:3000/post」にアクセスし、動作確認してください。
以下のように表示、投稿ができるかと思います。
これで、Next.jsとLaravelを使用して簡単な掲示板アプリの作成完了です。
以上です。