柳屋

ソースコードのリファクタからよもやままで

Lumenで継承を使ってAPIをサクッと作ってみた

LumenでAPIを作ったんですが、APIってCRUDベースで作れば事足りる機能がほとんどかなと思い、継承を使ってサクッと作ってみました。 継承を使えば記述量もぐっと減るし、うまく使えれば大変便利です それにバシーっと決まれば個人的にめっさ気持ち良いですよね

環境は以下のを使います

yanagiya.hatenadiary.com

構成

アセット 1.png

上記図の通り親クラスとなる ApiController に具体的な処理を書き それを継承するようにします 継承先はControllerとModelがあり紐づいてます

CRUDをベースとなるコントローラに作成する

メソッドはCRUDを基とし以下のようになっています

  • index→一覧
  • show→詳細
  • store→登録
  • update→更新
  • destroy→削除
app/Http/Controllers/ApiController.php
<?php

namespace App\Http\Controllers;

use Laravel\Lumen\Routing\Controller as BaseController;
use Illuminate\Http\Request;

class ApiController extends BaseController
{
    protected static $model = "";
    
    public function index()
    {
        $response = static::$model::all();
        return response()->json($response);
    }
    
    
    public function show($id = 0)
    {
        if(! $id) {
            $response["status"] = "ng";
            $response["messages"] = "引数が不正です";
            
            return response()->json($response);
        }
        $response = static::$model::find($id);
        
        if(count($response) < 1) {
            $response["status"] = "ng";
            $response["messages"] = "情報が見つかりません";
            
            return response()->json($response);    
        }
        
        $response["status"] = "ok";
        return response()->json($response);
    }
    
    
    public function store(Request $request)
    {
        $validator = static::$model::validation($request);

        $response = [];
        if ($validator->fails()) {
            $response["status"] = "ng";
            $response["messages"] = $validator->errors()->all();

            return response()->json($response);
        }
        
        
        static::$model::create($request->all());
        
        $response["status"] = "ok";
        return response()->json($response);
    }
    
    
    public function update(Request $request, $id)
    {
        $updates = $request->all();
        unset($updates['api_key']);

        $response = false;
        $response = static::$model::where('id', '=', $id)->update($updates);
        
        if ($response === 0) {
            $response["status"] = "ng";
            $response["messages"] = "パラメータが不正です";

            return response()->json($response);
        }
        
        $response["status"] = "ok";
        return response()->json($response);
    }
    

    public function destroy($id)
    {
        $result = static::$model::destroy($id);
        if ($result === 0) {
            $response["status"] = "ng";
            $response["messages"] = "パラメータが不正です";

            return response()->json($response);
        }
        
        $response["status"] = "ok";
        return response()->json($response);
    }
}

HTTPレスポンスコードの定義してへんやんとかページネーションは?とかのツッコミは一旦なしで

モデルの定義

    protected static $model = "";
    

上記の通り、モデルは継承先で定義するため、親クラスでは空で設定します

バリデーションの定義

<?php

namespace App\Http\Controllers;

use Laravel\Lumen\Routing\Controller as BaseController;
use Illuminate\Http\Request;

class ApiController extends BaseController
{
    〜省略〜        
    
    public function store(Request $request)
    {
        $validator = static::$model::validation($request);

        $response = [];
        if ($validator->fails()) {
            $response["status"] = "ng";
            $response["messages"] = $validator->errors()->all();

            return response()->json($response);
        }
        
        
        static::$model::create($request->all());
        
        $response["status"] = "ok";
        return response()->json($response);
    }
    〜省略〜
}

$validator = static::$model::validation($request);

バリデーションもモデル側で定義することにより継承をやりやすくしております

モデルの定義

app/Company.php
<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Validator;

class Company extends Model 
{
    protected $table = 'companies';
    protected $fillable = ['name'];
    
    public static function validation($request)
    {
        return Validator::make($request->all(), [
            'name' => 'required|max:256|unique:companies',
        ]);
    }
}

とりあえずCompanyモデルを例としています 上記の通りバリデーションを書いてます

LumenはデフォルトでModelディレクトリがないのでこのパスになってますが、Modelディレクトリ作っても良いかもですね。

コントロラーの定義

<?php

namespace App\Http\Controllers;

use App\Company;

class CompanyController extends ApiController
{
    protected static $model = "App\Company";
}

モデルと同様にCompanyコントローラを例としています

最初に作成した ApiController を継承しています そして$modelをComapnyモデルを使うように上書きしています

一点注意としてクラス名を動的に設定する場合はnamespaceを含め設定する必要があります

確認

これでAPIの作成は終わったのでcurlなりPostmanなりで ドメイン/company/ドメイン/company/storeにアクセスし正常に動作すれば完成です

コントロラーを増やしたければCompanyを基にモデルとコントロラーを作成すれば簡単に増やせます

以上です

;(function(document){ var pres = document.getElementsByTagName("pre") for(var i=pres.length; i--; ){  var el = makeOl(pres[i]) pres[i].appendChild(el) } function makeOl(pre){ if (pre.className.indexOf("gist") !== -1) { return } var ol = document.createElement("ol") , li = document.createElement("li") , df = document.createDocumentFragment() , br = pre.innerHTML.match(/\n/g) || 0 ol.className = "preLine" ol.setAttribute("role", "presentation") // no lang, no line-number if( pre.className && ! /lang-./.test(pre.className) ){ br.length += 1 } for(var i=br.length; i--; ){ var li2 = li.cloneNode(true) df.appendChild(li2) } ol.appendChild(df) return ol } })(document)