LaravelにはリソースAPIと呼ばれる機能が搭載されています。CRUDを提供するAPIをartisanコマンドひとつで作成できるという機能です。
ところが、どう頑張ってもAPIが正常に動作しないという問題に直面しました。どうしてもIDを指定してオブジェクトを返してくれる「show」が動作しないのです。ほかのメソッドは動作するのに。。今回はガチで困りまして、解決までに3時間もかかってしまいましたので、解決法をメモしておきます。
症状
artisanコマンドを使って、モデル・マイグレーション・リソースを作成しました。
php artisan make:model -mr PostCollection
通常通り、showメソッドでオブジェクトを返すように設定してみました。
/** * Display the specified resource. * * @param \App\PostCollection $postCollection * @return \Illuminate\Http\Response */ public function show(PostCollection $postCollection) { return $postCollection; }
しかし、なぜか空配列[]
しか帰ってきません。
ルート・マイグレーション・モデルの作成はうまく行っています。storeは動作しており、データの登録は問題なく行えます。Tinkerでテストしてみると、データを取得できます。
しかし、showだけが動かない。ついでにeditも動作しません。つまり、本来自動的に取得できるはずのオブジェクト(ここでは$postCollection)がなぜか取得できない状況が起こりました。
原因はルーティングのパスにあった
実は原因はルーティングのパスにありました。
問題解決前のルートがこちらです。route/api.phpに以下のように記載していました。
Route::resource('postcollection', "PostCollectionController");
解決後はこちら。
Route::resource('postCollection', "PostCollectionController");
違いが分かりますでしょうか?そうです。キャメルケースにしていなかったのが原因でした。
Route::resource('postCollection', "PostCollectionController");
実はRoute::resourceのパスに関しては、完全に自由だと思いこんでいたのです。モデル名はコントローラーの名前から自動的に取得され、モデルの取得もうまくいくと思っていました。
しかし、実はそうではないのです。APIに該当するモデルの選択はルート、つまりパスで行われているのです。
モデル名の推測に関しては、LaravelのドキュメントのRoute Model Bindingに記載されていました。
Implicit Binding
Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name. For example:Route::get(‘api/users/{user}’, function (App\User $user) {
return $user->email;
});
Since the $user variable is type-hinted as the App\User Eloquent model and the variable name matches the {user} URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated.
つまり、
- 変数の名前はEloquentモデルの名前から自動的に生成される
- どのインスタンスを生成するかは、リクエストURIから自動的に選択される
というわけです。なので、APIのURIはちゃんとキャメルケースで書かないとダメなわけです。クラスでモデルをuseしていたとしても、URIもきちんとルール通りに指定しないといけないのです。
引数の名前も要注意
さらにリソースコントローラーを利用するときは、引数の名前もルールに従う必要があります。
public function show(Post $post)
{
return $post;
}
$postを$hogeなどとほかの文字列に勝手に変えてしまうと、うまく取得できなくなります。
こちらもキャメルケースでルールに則ってコーディングする必要があります。モデル名を変更した際などは要注意です。
パスに複合語を使うときはキャメルケースを厳守!
リソースAPIを使うときは、きちんとURIを定義しましょう。複合語はキャメルケースを厳守しましょう。
今までMemoやNoteなど1語で表現できるルーティングばかり使っていたため気づきませんでした。ちゃんとドキュメントには書いてあったのですが、正直ここまで読んでなかったです(T_T)
これを読んでいたら3時間無駄にせずに済んだのに(T_T)
ドキュメントはちゃんと読もう!
コメント