Laravelを使用して、CRUD(作成、読み込み、更新、削除)ができるREST APIを作成します。
内容について、詳しく説明を行っていませんが、とりあえず手を動かしてLaravelでREST APIを作ってみたいといった際に、参考になれば幸いです。
環境について
Laravel環境は、以下のDocker開発環境を使用させていただきます。
Docker環境の構築については、リンク先にてご確認ください。
最強のLaravel開発環境をDockerを使って構築する
接続テスト
実際にAPIが作動しているか確認するために、接続テスト用のエンドポイントを作成します。
ブラウザで、「127.0.0.1/api/test」を開いた際に、「接続テスト成功!」が表示されると、接続テスト成功です。
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// 接続できているか確認用
Route::get('/test', function () { return '接続テスト成功!'; });
マイグレーションファイルの作成
データベースのテーブル定義を作成します。
「birdテーブル」と「typeテーブル」を作成します。
- birdテーブル
カラム名 | 型 | 文字数制限 | NULL許容 | 備考 |
---|---|---|---|---|
id | bigint | - | - | 自動生成されるID |
created_at | timestanp | - | ○ | レコードがインサートされた時間 |
updated_at | timestanp | - | ○ | レコードが更新された時間 |
deleted_at | timestanp | - | ○ | レコードが削除された時間(論理削除) |
name | varchar | 100文字 | - | 鳥の名前 |
type | bigint | - | - | typeテーブルとのリレーション |
- typeテーブル
カラム名 | 型 | 文字数制限 | NULL許容 | 備考 |
---|---|---|---|---|
id | bigint | - | - | 自動生成されるID |
created_at | timestanp | - | ○ | レコードがインサートされた時間 |
updated_at | timestanp | - | ○ | レコードが更新された時間 |
deleted_at | timestanp | - | ○ | レコードが削除された時間(論理削除) |
name | varchar | 100文字 | - | 鳥類 |
※ 環境についてで紹介したDocker環境の場合、コンテナ内のターミナルを操作する必要があります。
Dockerコンテナにターミナルをアタッチする
docker exec -it docker-laravel-app-1 sh
コンテナにアタッチしたことを確かめるため、Laravelのバージョンを確認する。
php artisan -v
Laravelのバージョンが表示されると、コンテナにアタッチできています。
この後のコマンド操作はアタッチしたシェルで作業します。
bardテーブルの作成
php artisan make:migration create_bird_table
「src/database/migrations/」フォルダ内の「YYYY_MM_DD_hhmmss_create_bird_table.php」を編集します。
※ コマンドの実施時間によってファイル名が異なります。
// 省略
public function up()
{
Schema::create('bird', function (Blueprint $table) {
$table->id();
$table->timestamps();
// --- 追加 ---
// ソフトデリート
$table->softDeletes()->comment('ソフトデリート');
// 名前(100文字)
$table->string('name', 100)->comment('名前');
// 種別(typeテーブルとのリレーション)
$table->bigInteger('type')->comment('種別');
// -----------
});
}
// 省略
typeテーブルの作成
php artisan make:migration create_type_table
「src/database/migrations/」フォルダ内の「YYYY_MM_DD_hhmmss_create_type_table.php」を編集します。
※ コマンドの実施時間によってファイル名が異なります。
// 省略
public function up()
{
Schema::create('type', function (Blueprint $table) {
$table->id();
$table->timestamps();
// --- 追加 ---
// ソフトデリート
$table->softDeletes()->comment('ソフトデリート');
// 名前(100文字)
$table->string('name', 100)->comment('名前');
// -----------
});
}
// 省略
シーダーファイルの作成
「birdテーブル」と「typeテーブル」のデータベースにインサートするデータを記述します。
birdテーブルのシーダー作成
php artisan make:seeder BirdTableSeeder
「src/database/seeders/」フォルダ内の「BirdTableSeeder.php」を編集します。
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
// --- 追加 ---
use Illuminate\Support\Facades\DB;
class BirdTableSeeder extends Seeder
{
public function run()
{
// --- 追加 ---
// 日本時間に設定
date_default_timezone_set('Asia/Tokyo');
DB::table('bird')->insert([
[
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'にわとり',
'type' => 1,
], [
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'イワトビペンギン',
'type' => 2,
], [
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'スズメ',
'type' => 3,
]
]);
// -----------
}
}
typeテーブルのシーダー作成
php artisan make:seeder TypeTableSeeder
「src/database/seeders/」フォルダ内の「TypeTableSeeder.php」を編集します。
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
// --- 追加 ---
use Illuminate\Support\Facades\DB;
class TypeTableSeeder extends Seeder
{
public function run()
{
// --- 追加 ---
// 日本時間に設定
date_default_timezone_set('Asia/Tokyo');
DB::table('type')->insert([
[
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'キジ科',
], [
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'ペンギン科',
], [
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
'name' => 'スズメ科',
]
]);
// -----------
}
}
シーダーファイルの読み込み設定
「src/database/seeders/」フォルダ内の「DatabaseSeeder.php」を編集します。
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
// --- 追加 ---
$this->call([
// 鳥テーブル
BirdTableSeeder::class,
// 分類テーブル
TypeTableSeeder::class,
]);
// -----------
}
}
マイグレーションとシーディングの実行
php artisan migrate --seed
データベースのマイグレーションとシーディングが正常に行われると、bardテーブルとtypeテーブルにデータが挿入されます。
モデルの作成
birdテーブルのモデルとtypeテーブルのモデルを作成します。
birdモデル
php artisan make:model Bird
「src/app/Models/」フォルダ内の「Bird.php」を編集します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
// --- 追加 ---
use Illuminate\Database\Eloquent\SoftDeletes;
class Bird extends Model
{
use HasFactory;
// --- 追加 ---
use SoftDeletes;
protected $table = 'bird';
protected $guarded = array('id');
// -----------
}
typeモデル
php artisan make:model Type
「src/app/Models/」フォルダ内の「Type.php」を編集します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
// --- 追加 ---
use Illuminate\Database\Eloquent\SoftDeletes;
class Type extends Model
{
use HasFactory;
// --- 追加 ---
use SoftDeletes;
protected $table = 'type';
protected $guarded = array('id');
// -----------
}
鳥の名前を取得するコントローラーの作成
php artisan make:controller BirdController --api
「src/app/Http/Controllers/」フォルダ内の「BirdController.php」を編集します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
// --- 追加 ---
use App\Models\Bird;
use App\Models\Type;
use Illuminate\Support\Facades\DB;
class BirdController extends Controller
{
public function index()
{
// --- 追加 ---
$result = Bird::select(
// birdテーブルのid
'bird.id as id',
// birdテーブルの鳥の名前
'bird.name as name',
// typeテーブルの鳥の分類名
'type.name as type'
)->join('type', function ($type) {
// bird.typeとtype.idとの紐付け
$type->on('bird.type', '=', 'type.id');
})->get();
return $result;
// -----------
}
// 省略
鳥の名前と種類を返すAPIを作成しました。
鳥の名前を取得するエンドポイントの定義
「src/routes/」フォルダ内の「api.php」を編集します。
// 省略
Route::prefix('bird')->group(function () {
// 鳥の名前と種類の表示
Route::get('/', 'App\Http\Controllers\BirdController@index');
});
// 省略
鳥の名前を取得するAPIのテスト
REST APIクライアントツール(postmanや、VS Code拡張のThunder Clientなど。例では、Thunder Clientを使用しています。)で、「127.0.0.1/api/bird」にGETリクエストを送ると、birdテーブルのid、鳥の名前、typeテーブルの分類名がJSON形式で表示されます。
※ APIにリクエストを送信した際に、サーバーエラーが発生する場合は、Laravelのキャッシュクリアを試してみてください。
参考:Laravel 粘着質なcacheを削除しよう!
鳥の名前と種類名を登録するコントローラーの作成
「src/app/Http/Controllers/」フォルダ内の「BirdController.php」を編集します。
バリデーションとして、鳥の種類名と名前が存在しない場合は、登録せずに、エラーレスポンスを返すようにしています。
// 省略
public function store(Request $request)
{
// --- 追加 ---
// 登録したい内容を受け取る
$form = $request->all();
// バリデーション
// 鳥の種類名が存在するか
if (!isset($form['type'])) {
return response()->json(["鳥の種類名が存在しません"], 400);
}
// 鳥の名前が存在するか
if (!isset($form['name'])) {
return response()->json(["鳥の名前が存在しません"], 400);
}
// トランザクション
DB::beginTransaction();
// 日本時間に設定
date_default_timezone_set('Asia/Tokyo');
try {
// 先に種類を登録
$type = new Type();
$type->fill([
// 登録日時
'created_at' => date("Y/m/d H:i:s"),
// 更新日時
'updated_at' => date("Y/m/d H:i:s"),
// 種類名
'name' => $form['type'],
])->save();
// 鳥の種類を登録
$bird = new Bird();
$bird->fill([
// 登録日時
'created_at' => date("Y/m/d H:i:s"),
// 更新日時
'updated_at' => date("Y/m/d H:i:s"),
// 鳥の名前
'name' => $form['name'],
// 鳥の種類
'type' => $type->id,
])->save();
// コミット
DB::commit();
return $bird;
} catch (Exception $exception) {
// 例外処理
// ロールバック
DB::rollBack();
throw $exception;
}
// -----------
}
// 省略
鳥の名前と種類名を登録するエンドポイントの定義
「src/routes/」フォルダ内の「api.php」を編集します。
// 省略
Route::prefix('bird')->group(function () {
// 鳥の名前と種類の表示
Route::get('/', 'App\Http\Controllers\BirdController@index');
// 鳥の名前と種類を登録
Route::post('/', 'App\Http\Controllers\BirdController@store');
});
// 省略
鳥の名前と種類名を登録するAPIのテスト
REST APIクライアントツールで「127.0.0.1/api/bird」にPOSTリクエストを送ると、鳥の名前と種類が登録できます。
- リクエストボディ(JSON)
{
"type": "オウム科",
"name": "オカメインコ"
}
DBを見ると、POSTリクエストのボディの内容が登録されていることが確認できます。
鳥の名前と種類名を編集するコントローラーの作成
「src/app/Http/Controllers/」フォルダ内の「BirdController.php」を編集します。
バリデーションとして、birdテーブルに編集対象が存在するか、鳥の種類名と名前が存在しない場合は、登録せずに、エラーレスポンスを返すようにしています。
// 省略
public function update(Request $request, $id)
{
// --- 追加 ---
// 登録したい内容を受け取る
$form = $request->all();
// バリデーション
// 編集したいデータが存在するか
if (!Bird::where('id', $id)->exists()) {
return response()->json(["編集対象のレコードが存在しません"], 400);
}
// 鳥の種類名が存在するか
if (!isset($form['type'])) {
return response()->json(["鳥の種類名が存在しません"], 400);
}
// 鳥の名前が存在するか
if (!isset($form['name'])) {
return response()->json(["鳥の名前が存在しません"], 400);
}
// トランザクション
DB::beginTransaction();
// 日本時間に設定
date_default_timezone_set('Asia/Tokyo');
try {
// birdテーブルのid検索
$bird = Bird::find($id);
// アップデート処理を行う
$bird->fill([
// 更新日時
'updated_at' => date("Y/m/d H:i:s"),
// 鳥の名前
'name' => $form['name'],
])->update();
// typeデーブルのid検索
$type = Type::find($bird->type);
// アップデート処理を行う
$type->fill([
// 更新日時
'updated_at' => date("Y/m/d H:i:s"),
// 鳥の種類
'name' => $form['type'],
])->update();
// コミット
DB::commit();
return response()->json([
"bird" => $bird,
"type" => $type
], 200);
} catch (Exception $exception) {
// 例外処理
// ロールバック
DB::rollBack();
throw $exception;
}
// -----------
}
// 省略
鳥の名前と種類名を編集するエンドポイントの定義
「src/routes/」フォルダ内の「api.php」を編集します。
// 省略
Route::prefix('bird')->group(function () {
// 鳥の名前と種類の表示
Route::get('/', 'App\Http\Controllers\BirdController@index');
// 鳥の名前と種類を登録
Route::post('/', 'App\Http\Controllers\BirdController@store');
// 鳥の名前と種類を更新
Route::put('/update/{id}', 'App\Http\Controllers\BirdController@update');
});
// 省略
鳥の名前と種類名を編集するAPIのテスト
REST APIクライアントツールで「127.0.0.1/api/bird/update/2」にPUTリクエストを送ると、birdテーブルのidが2番(ペンギン科、イワトビペンギン)の鳥の名前と種類が編集できます。
- リクエストボディ(JSON)
{
"type": "ペンギン目ペンギン科",
"name": "キングペンギン"
}
DBを見ると、PUTリクエストのボディの内容に更新されていることが確認できます。
鳥の名前と種類名を論理削除するコントローラーの作成
「src/app/Http/Controllers/」フォルダ内の「BirdController.php」を編集します。
// 省略
public function destroy($id)
{
// --- 追加 ---
// バリデーション
// 削除対象のレコードが存在するか
if (!Bird::where('id', $id)->exists()) {
return response()->json(["削除対象のレコードが存在しません"], 400);
}
// トランザクション
DB::beginTransaction();
// 日本時間に設定
date_default_timezone_set('Asia/Tokyo');
try {
// 削除対象のbirdレコードに紐づくtypeレコードのidを求める
$TypeId = Bird::select('type')->where('id', $id)->first();
// 削除したいbirdレコードを探し、削除
Bird::find($id)->delete();
// birdレコードに紐づくtypeレコードも削除
Type::find($TypeId->type)->delete();
// コミット
DB::commit();
return response()->json(['削除完了'], 200);
} catch (Exception $exception) {
// 例外処理
// ロールバック
DB::rollBack();
throw $exception;
}
// -----------
}
// 省略
鳥の名前と種類名を論理削除するエンドポイントの定義
「src/routes/」フォルダ内の「api.php」を編集します。
// 省略
Route::prefix('bird')->group(function () {
// 鳥の名前と種類の表示
Route::get('/', 'App\Http\Controllers\BirdController@index');
// 鳥の名前と種類を登録
Route::post('/', 'App\Http\Controllers\BirdController@store');
// 鳥の名前と種類を更新
Route::put('/update/{id}', 'App\Http\Controllers\BirdController@update');
// 鳥の名前と種類を論理削除
Route::delete('/destroy/{id}', 'App\Http\Controllers\BirdController@destroy');
});
// 省略
鳥の名前と種類名を編集するAPIのテスト
REST APIクライアントツールで「127.0.0.1/api/bird/destroy/4」にDELETEリクエストを送ると、birdテーブルのidが4番(オウム科、オカメインコ)のレコードが論理削除されます。
DBを見ると、birdテーブルの「オカメインコ」とtypeテーブルの「オウム科」のレコードのdeleted_atに日付が入っていることが確認できます。
以上で、Laraveで一通りのCRUD操作を行うREST APIができます。