概要
今回の記事ではバックエンド部分の開発について記していきたいと思います。
環境
Laravel(11.29.0)
MAMP
プロジェクトの作成
Laravelプロジェクト立ち上げ
composer create-project --prefer-dist laravel/laravel baselog-backend
参考 --prefer-distとは
データベース設定
.envファイルのデータベース接続設定を以下のように更新します。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=baselog
DB_USERNAME=root
DB_PASSWORD=
Laravel Sanctumの導入
api.phpのインストール
php artisan install:api
参考
参考 Laravel API Sanctumの仕組みについて
https://qiita.com/ucan-lab/items/3e7045e49658763a9566
今回はAPIトークン認証を使用したのですが、セキュリティの観点からSPA認証(クッキー認証)を利用した方が良い場合もあるようです。
Laravel Sanctumの設定
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
HasApiTokensトレイをUserモデルに追加します。
参考
モデルの作成
以下のコマンドでモデルとマイグレーションファイルを作成
php artisan make:model Game -m
まずは試合結果を保存するためのカラムを定義していきます。
public function up(): void
{
Schema::create('games', function (Blueprint $table) {
$table->id();
$table->date('date');
$table->string('home_team');
$table->string('away_team');
$table->timestamps();
});
}
補足:voidはメソッドが何も値を返さないことを明示的に示すものであり、省略しても問題ありません。
マイグレーションを実行してテーブルを作成します。
php artisan migrate
コントローラーの作成
続いて、試合結果を保存するためのコントローラを作成します。
php artisan make:controller GameController
GameController.phpに試合結果を保存するためのメソッドを定義します。
public function store(Request $request)
{
$request->validate([
'date' => 'required|date',
'home_team' => 'required|string',
'away_team' => 'required|string',
'home_total_score' => 'required|integer',
'away_total_score' => 'required|integer',
'home_total_hits' => 'required|integer',
'away_total_hits' => 'required|integer',
'home_total_errors' => 'required|integer',
'away_total_errors' => 'required|integer',
]);
for ($inning = 1; $inning <= 9; $inning++) {
$request->validate([
"home_inning_{$inning}" => 'required|integer',
"away_inning_{$inning}" => 'required|integer',
]);
}
$game = Game::create($request->all());
return response()->json(['message' => 'Game result saved collectlly!', 'data' => $game], 201);
}
まずリクエストのバリデーションを行います。
$request->all()でリクエストから送られてきたすべての入力データを配列として取得し、Game::createメソッドに渡しています。
そして、createメソッドを使用して、新しいGameレコードを作成し、データベースに保存します。
最後に、APIのレスポンスをJSON形式で返しています。
(createメソッドではなくsaveメソッドでもコントローラーのアクションを実装することができるが、saveメソッドを使う場合、各プロパティに手動でデータを割り当てる必要があるため冗長になってしまう。カラムが多く場合にはcreateメソッドの方が簡潔)
APIルートの設定
routes/api.phpに試合結果の保存用エンドポイントを追加します。
use App\Http\Controllers\GameController;
Route::post('/games', [GameController::class, 'store']);
Route::postは、POSTリクエストのルートを定義するためのLaravelのメソッドです。
/gamesにPOSTリクエストが送られた時にこのルートがトリガーされます。GameController::classでGameControllerクラスを参照し、storeメソッドにルーティングしています。
CORSの設定
CORSはブラウザが異なるオリジン間のリクエストを許可するかどうかを制御する仕組み。
'allowed_origins' => ['http//localhost:3000'],
すべてのオリジンを許可したい場合は*を使うことで許可することができます。
参考
アクションの追加
新しい試合結果を保存するためのアクションしか準備していなかったので、試合結果の一覧の取得、特定の試合結果の取得、試合結果の更新、試合結果の削除この4つのアクションを追加してみたいと思います。
public function index()
{
$games = Game::all();
return response()->json($games);
}
public function show($id)
{
$game = Game::find($id);
if (is_null($game)) {
return response()->json(['message' => 'Not Found'], 404);
}
return response()->json($game);
}
public function update(Request $request, $id)
{
$game = Game::find($id);
if (is_null($game)) {
return response()->json(['message' => 'Not Found'], 404);
}
$game->update($request->all());
return response()->json($game);
}
public function destroy($id)
{
$game = Game:find($id);
if (is_null($game)) {
return response()->json(['message' => 'Not Found'], 404);
}
$game->delete();
return response()->json(null, 204);
APIルートの追加
コントローラーのアクションの追加に伴ってルーティングを再度設定していきます。
Route::post('/games', [GameController::class, 'store']);//試合結果の追加
Route::get('/games', [GameController::class, 'index']);//試合結果の取得
Route::get('/games/{id}', [GameController::class, 'show']);//特定の試合結果の取得
Route::put('/games/{id}', [GameController::class, 'update']);//試合結果の更新
Route::delete('/games/{id}', [Gamecontroller::class, 'destroy']);//試合結果の削除
このようになりますが、実は上記のような基本的なCRUD操作はまとめて定義することができます。
Route::apiResource('games', GameController::class);
参考
APIテスト
POSTMANを利用して各エンドポイントが正しく動作するか確認しました。
参考文献