
Laravelは簡単にRestful APIを実装できるようになっています。
バージョン
- PHP 7.1.27
- Laravel 5.8.8
もくじ
実装のポイント
コントローラを作る時に–resourceオプション
$ php artisan make:controller MonsterController --resource
ルートにresourceのメソッドを指定する
$ vi ./routes/api.php
Route::resource('monsters', 'MonsterController');
これだけです。
RESTfulの特徴
メソッドで動作を変化させるシンプル設計
- 一覧取得 index()
GET /api/monsters/ - IDを指定して取得
GET /api/monsters/{id} - 新規追加
POST /api/monsters/ - 更新
PUT /api/monsters/ - IDを指定して削除
DELETE /api/monsters/{id}
URLはそろえてHTTPメソッドで動作を変化させる
ステートレス
セッションなどの状態を管理せず、リクエストで必ず処理が完了する
URLの設計
- https://api.example.net/
apiとすぐにわかるURLにする。 - 拡張子をつけてはいけない
- URLが変わることがあってはいけない
- URLは複数名刺にする、バージョンを含める、動詞はつけない
http://api.example.net/v1/monsters/
// 今回の記事は良くないURLになっています。
モデルの作成
$ mkdir ./app/Models $ php artisan make:model Models/Monster -m Model created successfully. Created Migration: 2019_03_31_075556_create_monsters_table
プライマリキーの設定
$ vi ./app/Models/Monster.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Monster extends Model
{
protected $primaryKey = 'monster_id';
}
テーブルの定義
$ vi ./database/migrations/2019_03_31_082838_create_monsters_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMonstersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('monsters', function (Blueprint $table) {
$table->bigIncrements('monster_id');
$table->string('name');
$table->string('voice');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('monsters');
}
}
シーダファイルの作成
$ php artisan make:seeder MonstersTableSeeder
$ vi ./database/seeds/MonstersTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class MonstersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table("monsters")->insert([
"monster_id" => 1,
"name" => "komaさん",
"voice" => "もんげぇ",
"created_at" => new DateTime(),
"updated_at" => new DateTime()
]);
DB::table("monsters")->insert([
"monster_id" => 1,
"name" => "Nyanchuuさん",
"voice" => "ミーだにゃぁ",
"created_at" => new DateTime(),
"updated_at" => new DateTime()
]);
}
}
レコードの削除+テーブルの作成
$ php artisan migrate:refresh --seed
シーダファイルによるインサート
$ php artisan db:seed --class=MonstersTableSeeder
ミドルウェアの作成
JSONの日本語文字化け防止
(外部サイト:https://nextat.co.jp/staff/archives/203)
$ php artisan make:middleware UnescapeJsonResponse
$ vi ./app/Http/Middleware/UnescapeJsonResponse.php
<?php
namespace App\Http\Middleware;
use Closure;
use Symfony\Component\HttpFoundation\JsonResponse;
class UnescapeJsonResponse
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
// JSON以外はそのまま
if (!$response instanceof JsonResponse) {
return $response;
}
// エンコードオプションを追加して設定し直す
$newEncodingOptions = $response->getEncodingOptions() | JSON_UNESCAPED_UNICODE;
$response->setEncodingOptions($newEncodingOptions);
return $response;
}
}
Laravel Kernelに追加
$ vi ./app/Http/Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
※下記を追加
'UnescapeJsonResponse' => \App\Http\Middleware\UnescapeJsonResponse::class,
];
コントローラの作成
$ php artisan make:controller MonsterController --resource
初期状態確認
$ cat ./app/Http/Controllers/MonsterController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MonsterController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
コントローラ内容変更
$ vi ./app/Http/Controllers/MonsterController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Monster;
class MonsterController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function __construct()
{
$this->middleware('UnescapeJsonResponse');
}
public function index()
{
$items = Monster::all();
return response()->json($items);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'voice' => 'required|max:255',
]);
$monster = new Monster();
$monster->name = $request->name;
$monster->voice = $request->voice;
$monster->save();
return response()->json();
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$item = Monster::find($id);
return response()->json($item);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required|max:255',
'voice' => 'required|max:255',
]);
$monster = Monster::find($id);
$monster->name = $request->name;
$monster->voice = $request->voice;
$monster->save();
return response()->json();
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $id)
{
$monster = Monster::find($id);
$monster->delete();
return response()->json();
}
}
ルート設定
$ vi ./routes/api.php
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
※下記を追加
Route::resource('monsters', 'MonsterController');
ルーティング確認
$ php artisan route:list
+--------+-----------+-----------------------------+------------------+------------------------------------------------+--------------------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+-----------------------------+------------------+------------------------------------------------+--------------------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/monsters | monsters.index | App\Http\Controllers\MonsterController@index | api,UnescapeJsonResponse |
| | POST | api/monsters | monsters.store | App\Http\Controllers\MonsterController@store | api,UnescapeJsonResponse |
| | GET|HEAD | api/monsters/create | monsters.create | App\Http\Controllers\MonsterController@create | api,UnescapeJsonResponse |
| | GET|HEAD | api/monsters/{monster} | monsters.show | App\Http\Controllers\MonsterController@show | api,UnescapeJsonResponse |
| | PUT|PATCH | api/monsters/{monster} | monsters.update | App\Http\Controllers\MonsterController@update | api,UnescapeJsonResponse |
| | DELETE | api/monsters/{monster} | monsters.destroy | App\Http\Controllers\MonsterController@destroy | api,UnescapeJsonResponse |
| | GET|HEAD | api/monsters/{monster}/edit | monsters.edit | App\Http\Controllers\MonsterController@edit | api,UnescapeJsonResponse |
| | GET|HEAD | api/user | | Closure | api,auth:api |
+--------+-----------+-----------------------------+------------------+------------------------------------------------+--------------------------+
index()確認

http://IPアドレス/api/monsters
show()確認

http://IPアドレス/api/monsters/2


