Laravelのルーティングは「上から設定された順番に実行される」という特性がある。
今回は、このルーティングの優先度によって生じるエラーの例と対応策を紹介する。
間違った点があればご指摘いただけますと幸いです。
エラー発生例
Laravelのルーティングは、「上から登録されている順番に実行される」という特性がある。
この特性を知らずにルーティングを設定すると予期しないエラーが発生する恐れがある。
特に、ルートパラメータを使用するときにエラーが起きやすい。
例えば、以下のルーティングファイルで、「/user/create」にアクセスしようとすると、404エラーが発生する。
Route::get('/user/{id}', [UserController::class, 'show']);
Route::get('/user/create', [UserController::class, 'create']);
エラー要因
ルーティングは上から順番に実行されるため、1つ上の「/user/{id}」を実行しまったのが原因である。
「/user/create」の「create」が「/user/{id}」のルートパラメータidと同じ位置にあるため、createがルートパラメータとして渡されてしまう。
その結果、意図しないコントローラ内のアクションメソッドを実行してしまいエラーに繋がってしまった。
対応策
ルーティングの優先度による上記のようなエラーを避けるための対応策をいくつか紹介する。
順番を変える
ルーティングの順番を変えると簡単にエラーを回避できる。
Route::get('/user/create', [UserController::class, 'create']);
Route::get('/user/{id}', [UserController::class, 'show']);
しかし、この方法だとルーティングを追加・更新する度に順番を入れ替える必要も出てくるので、あまりおすすめはできない。
そこで、次に紹介するwhereメソッドを使用した正規表現パターンによる制約がおすすめである。
正規表現で制約を付ける
ルートインスタンスのメソッドを使用することで、指定したルートパラメータに正規表現パターンの制約を付けることができる。
whereメソッド (単体で制約したい場合)
ルーティング単体で使用するルートパラメータに制約を付けたい場合はwhereメソッドを使用する。
例えば、ルートパラメータidが数字の時しか実行しないようにしたい場合、以下のようにwhereメソッドで制約を付けることができる
Route::get('/user/{id}', [UserController::class, 'show'])
->where('id', '[0-9]+');
Route::get('/user/create', [UserController::class, 'create']);
patternメソッド (グローバルで制約したい場合)
グローバルでルートパラメータに制約を付けたい場合はpatternメソッドを使用する。
patternメソッドは App\Providers\RouteServiceProviderクラス内のbootメソッドで定義する。
public function boot(): void
{
Route::pattern('id', '[0-9]+');
}
上記の正規表現パターン定義によって、ルーティングで使用するルートパラメータidは数値のみしか受け付けないという制約が自動的に適用される。
Route::get('/user/{id}', [UserController::class, 'show'])
// idが数値の場合のみ受け付ける
「id」のように同じ名前のルートパラメータに同じ正規表現パターンの制約を付けたい場合は、whereメソッドを用いて1つ1つ単体で定義するより、patternメソッドを用いてbootメソッド内で一括でパターン定義する方が便利である。
参考サイト
- Laravel 8.x ルーティング
- Laravel 404 Not Foundエラーはルーティング順に原因があった