太陽がまぶしかったから

C'etait a cause du soleil.

PHP 初心者による Laravel 入門 その5 RESTful API と MySQL 操作

Laravel で RESTful API 作成

 前回までで MySQL の Docker コンテナを作成してPHP Laravel のコンテナから接続できるようにした。

 いまどきの Single Page Application 構成を見据えて View は React で作ることにしたため、 Laravel では API を通じたデータの入出力に専念させたい。このような用途に利用されるのが、 RESTful API である。RESTful API とは REpresentational State Transfer の原則に基づいて設計された API で一意の URI と HTTP メソッドによってリソースへのアクセスを提供する。CRUD と HTTP メソッドの関係は以下の通り。

CRUD 意味 メソッド 備考
Create 作成 POST / PUT 指定IDが存在しなれば新規作成する更新(いわゆる UPSERT) は PUT
Read 読み込み GET Content-Type: application/json 形式で取得
Update 更新 PUT 更新後の結果を返却する
Delete 削除 DELTE 論理削除は PUT( GEC の LB が対応してないので DELTE は使わないほうよいそう )

 これらの処理を Laravel で実装していく。

artisan で REST コントローラーを生成

 Laravel では artisan によって RESTful API に適したコントローラーのテンプレートを生成することができる。

$ docker exec -it docker_web bash
[root@2665067dae23 laravelapp]# php artisan make:controller CompnayApiController --resource

 上記コマンドを実行すると、 app/http/Controllers 内に指定したコントローラーが生成されているので、 DB へのアクセス処理を書いていく。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class CompanyApiController extends Controller
{
    public function index()
    {
        $item = DB::table('company')
            ->orderBy('company_id','desc')
            ->get(['company_id','company_name']);
        return response(json_encode($item), 200)
            ->header('Content-Type', 'application/json');
    }

    public function show($id)
    {
        $item = DB::table('company')
            ->where('company_id', $id)
            ->first(['company_id','company_name']);
        if($item !== null) {
          return response(json_encode($item), 200)
            ->header('Content-Type', 'application/json');
        } else {
            return response('', 404);
        }
    }
}

 それぞれを web.php で紐付ける。

<?php


Route::get('/', function () {
    return view('welcome');
});
Route::get('/api/company', 'CompanyApiController@index');
Route::get('/api/company/{id}', 'CompanyApiController@show');

 このようにすることで、 {endpoint}/api/company/ への GET アクセスで一覧データ、{endpoint}/api/company/{id} なら個別データを JSON で戻せるようになる。

 さらに create() では MySQL への Insert を行って自動採番されたIDを含むレコードを返却させる。 insertGetId($param); が便利。

    public function create(Request $req)
    {
        $param = [
            'company_name' => $req->input('company_name')
        ];
        $last_id = DB::table('company')->insertGetId($param);
        
        $item = [
            'company_id' => $last_id,            
            'company_name' => $req->input('company_name')
        ];
        return response(json_encode($item), 201);
    }

 こちらは POST メソッドに紐付ける。

Route::post('/api/company', 'CompanyApiController@create');

 POSTを実行する際にはデフォルトで CSRF 対策が必須となっているが、 状態を持たない RESTful API において CSRF のトークンを求めるのは適さないため、 app/http/Middleware/VerifyCsrfToken.php に以下の記述を行って除外対象とする。

    protected $except = [
        'api/*'
    ];

curl と jq で Restful API のテスト

 GETメソッドであればブラウザから直接アドレスを叩けばよいが、 POST についてブラウザが生成するのは面倒であるため curl コマンドと jq コマンドのテストを行う。 jq については homebrew からインストールしておく必要がある。

$ curl localhost:50000/api/company | jq -r
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   422    0   422    0     0    135      0 --:--:--  0:00:03 --:--:--   135
[
  {
    "company_id": 5,
    "company_name": "株式会社幽霊的身体"
  },
  {
    "company_id": 4,
    "company_name": "株式会社現代視覚"
  },
  {
    "company_id": 3,
    "company_name": "現代空間株式会社"
  },
  {
    "company_id": 2,
    "company_name": "現代日本株式会社"
  },
  {
    "company_id": 1,
    "company_name": "現代観光株式会社"
  }
]

 POSTコマンドを実行する。-X でメソッド -H リクエストヘッダを指定してペイロードを -d で指定している。

$ curl localhost:50000/api/company -X POST -H 'Content-Type:application/json' -d '{"company_name":"追加株式会社"}' | jq -r
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   108    0    71  100    37     21     11  0:00:03  0:00:03 --:--:--    21
{
  "company_id": 77,
  "company_name": "追加株式会社"
}

 データベースを覗くと上記のデータが登録されている。エラーハンドリングなどの課題が残っているが、とりあえずは表示と登録の API が動くことを確認した。次回はこの API を React から利用することは考える。