
Laravelのルーティングは開発を始めたばかりの人は、「なんとなく動くからいいや」と思って使っている機能のひとつかもしれない。
そんなLaravelのルーティングについてこの記事では、Laravelのルーティングについて、基本から詳しめにわかりやすく整理していこうと思います。
INDEX
ルーティングとは何か?
ルーティングとは、ユーザーからのリクエスト(URL)を、Laravel側の処理に紐付けする仕組みです。
たとえば、/about
というエンドポイント(アクセス先のURL)にリクエストが来たら、AboutController
の index()
メソッドを実行する──というような動作を定義できます。
エンドポイント(endpoint)ってなに?
クライアントがアクセスするURLの到達点。
「このURLを叩いたら、こういう処理がされるよ」っていう接続口みたいなやつ。
GET /api/users
→ ユーザー一覧を取得するエンドポイントPOST /login
→ ログイン処理を行うエンドポイント
ルート定義
Laravelの基本的なルート定義は以下のような形になります。
use Illuminate\Support\Facades\Route;
Route::get('/hello', function () {
return 'Hello, Laravel!';
});
この場合、/hello
にGETアクセスされたときに、"Hello, Laravel!" という文字列を返す。
こう記述すると https://自分で取得したドメイン/hello
にアクセスすると、Hello Laravelという文字列が表示されます。
Laravelでは、HTTPメソッドごとにルート定義を使い分けられます。
Route::get()
:主にデータの取得に使います(読取り専用)。Route::post()
:新しいデータの作成など。サーバー側の状態が変わる。Route::put()
/Route::patch()
:データの更新用。厳密には用途に違いがあります。Route::delete()
:データの削除。Route::match(['get', 'post'], ...)
:複数メソッド対応。Route::any()
:全部のメソッドに反応。テスト用や雑な用途向け。
※ HTTPメソッドにはそれぞれ意味や“設計上のルール”がありますが、機会があればAPI設計と絡めて記事を書きたいと思います。
コントローラーを使ったルーティング
実際の開発では、無名関数よりもコントローラーを使うケースが一般的。
Route::get('/users', [UserController::class, 'index']);
このように書くと、UserController
の index()
メソッドが呼び出される。App\Http\Controllers\UserController
にIndexメソッドが生えてれば処理が実行されます。
ルートパラメータとモデルバインディング
プレースホルダ付きルート
Route::get('/users/{id}', [UserController::class, 'show']);
URLの中に {id}
のようなプレースホルダを入れることで、
例えば /users/42
にアクセスされたときに、show($id)
に 42
が渡ってきます。
// app/Http/Controllers/UserController.php
public function show($id) # ここの$idに42が渡ってくるよ!
{
$user = User::findOrFail($id);
// 必要に応じて、データをレスポンスやビューへ渡す
}
こういった形式のURLの {}
の部分は 「パスパラメータ(path parameter)」 と呼ばれます。
リクエストされたURLの“どの部分を変数として受け取るか”を指定する仕組みです。
モデルバインディング
Laravelの便利な機能として、「ルートモデルバインディング」があります。{user}
の部分にIDを指定すると、自動的に User
モデルのインスタンスが注入されます。
簡単なものを作る時に便利かもしれませんね。
Route::get('/users/{user}', [UserController::class, 'show']);
// app/Http/Controllers/UserController.php
use App\Models\User;
public function show(User $user) {
return view('user.show', compact('user'));
}
モデルを明示的に取得する必要がなくなるので、コードもスッキリします。
Route::resource() の便利さと注意点
Laravelには、RESTfulなルートを一気に定義できる Route::resource()
があります。
Route::resource('posts', PostController::class);
これだけで以下の7つのルートが生成される:
HTTP | URL | アクション | 用途 |
---|---|---|---|
GET | /posts | index | 一覧表示 |
GET | /posts/create | create | 作成フォーム |
POST | /posts | store | 作成処理 |
GET | /posts/{post} | show | 詳細表示 |
GET | /posts/{post}/edit | edit | 編集フォーム |
PUT/PATCH | /posts/{post} | update | 更新処理 |
DELETE | /posts/{post} | destroy | 削除処理 |
REST(Representational State Transfer)とは、Webの設計原則のひとつで、
「URLとHTTPメソッドを組み合わせて、リソース(=データ)を操作する」考え方です。
GET /posts
で一覧取得、POST /posts
で作成、DELETE /posts/1
で削除…といった形で、ルール化されています。
LaravelではこのRESTのルールに従ったルーティングを「resource()」で簡単に作れます。
LaravelはRestと親和性が高いことが伺えますね。
必要なアクションだけ使いたい場合は only()
を使うと便利。
Route::resource('posts', PostController::class)->only(['index', 'show']);
7つもルート要らないよ!!って人は確実にいるので、こうやって利用するルートを限定することもできるんですね。
名前付きルートとroute()ヘルパー
ルートに名前をつけると、URLを直接書かずにリンク先を指定できます。
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
エンドポイントに影響があるわけではないですが、実はこれってとっても便利なんですよ。
Route::get('/dashboard', [DashboardController::class, 'index']);
と名前をつけずにルートを定義していました。
で、名前をつけてないので、至る所にこんな実装があったとします。
// たとえばコントローラーとかビューで
return redirect('/dashboard');
<a href="/dashboard">ダッシュボード</a>
この状態でえらいおじさんが
🧓 「このurlのdashbordさー、homeにしてくんない?」
どこに /dashboard
書いたか全部探す旅が始まる😱
- Bladeテンプレート全部検索
- コントローラーの redirect() チェック
- JavaScriptで埋め込まれてないかチェック
- ページネーションやリンク生成も再確認
ということが起きるので、nameは設定しておくと地味に便利です。必ず設定しましょう。
ミドルウェアとルート制御
Laravelでは、「このルートは特定の条件を満たしたユーザーだけがアクセスできるようにしたい」といった制限をかけたいときに、ミドルウェア(middleware)を使います。
たとえば、ログインしていないユーザーをアクセス禁止にしたい場合は、auth
ミドルウェアを使います。
Route::middleware(['auth'])->group(function () {
Route::get('/profile', [ProfileController::class, 'show']);
});
このように書くと、/profile
へのアクセスにはログイン済みであることが必須になります。auth
ミドルウェアが「ログインしてない人はリダイレクトさせる」処理を自動で担当してくれるわけです。
この仕組みは、Laravel Breeze や Jetstream などの公式スタートキットでも標準で使われており、
認証付きページや会員専用ページなどを作るときの基本パターンとしてよく使われます。
マジで爆速でLaravelエンジニアになる方法はこれしかない(無料)
LaravelBreezeについては↑で構築ハンズオンやってます。爆速でLaravelエンジニアになりたい方はどうぞ。
Route::group() でルートをまとめよう
Laravelでは、複数のルートに対して共通の条件や設定をまとめて指定したいときに、Route::group()
を使います。
最もよく使われるのは以下の3つ:
- URLの先頭に共通の文字列をつけたい(
prefix
) - ミドルウェアをまとめて適用したい(
middleware
) - 名前付きルートの接頭語をつけたい(
as
)
例1:URLに共通の prefix をつける
Route::prefix('admin')->group(function () {
Route::get('/users', [AdminUserController::class, 'index']);
Route::get('/posts', [AdminPostController::class, 'index']);
});
これで定義されるルートは:
/admin/users
/admin/posts
いちいち admin/
って書かなくて済むし、保守性が爆上がり。
例2:共通のミドルウェアをまとめてかける
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/settings', [SettingsController::class, 'edit']);
});
すべてのルートに auth
と verified
ミドルウェアが適用されます。
「ログインしてて、メール認証も済んでる人だけアクセスOK」のゾーンがまとめて作れて便利。
これが一番良く使うパターンかも知れない。
例3:名前付きルートの prefix を設定する
Route::name('admin.')->prefix('admin')->group(function () {
Route::get('/users', [AdminUserController::class, 'index'])->name('users.index');
});
このようにすると、ルート名は自動的に admin.users.index
になります。
例4:これらを全部まとめて使うとこうなる
Route::prefix('admin')
->name('admin.')
->middleware('auth')
->group(function () {
Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
Route::get('/users', [AdminUserController::class, 'index'])->name('users.index');
});
URLは: /admin/dashboard
ルート名は: admin.dashboard
ミドルウェア: auth
(ログイン必須)
ルーティング時のバリデーション
Laravelのルーティングでは、パスパラメータに対してバリデーションルールを設定することができます。
これは、「変な値が来たら最初から処理しない」という安全設計につながる便利な機能です。
正規表現でパラメータを制御する: where()
Route::get('/users/{id}', [UserController::class, 'show'])
->where('id', '[0-9]+');
このように書くことで、{id}
に対して **「数字だけ」**という制限をかけられます。/users/abc
のようなリクエストはこのルートにマッチせず、404になります。
数字だけ許可:whereNumber()
Route::get('/products/{product}', [ProductController::class, 'show'])
->whereNumber('product');
[0-9]+
と書く代わりに、Laravelには数字専用のショートカットメソッドがあります。
これで同じことがよりシンプルに書けます。
他にも使えるバリデーションメソッド
メソッド | 説明 |
---|---|
whereAlpha() | アルファベットのみ許可 |
whereAlphaNumeric() | 英数字を許可 |
whereIn('param', ['a', 'b', 'c']) | 特定の候補だけ許可(Laravel 10〜) |
routes/web.php と routes/api.php の違い
Laravelの routes
ディレクトリには、いくつかルート定義ファイルが用意されています。
その中でも特に使うのが web.php
と api.php
。
どっちも「ルーティングを書く場所」なんだけど、使いどころと裏で働いてる仕組みが違うんです。
主な違い
特徴 | web.php | api.php |
---|---|---|
想定される用途 | 通常のWebページ(HTML、Blade等) | API通信(JSONなど) |
自動適用されるミドルウェア | web ミドルウェアグループ | api ミドルウェアグループ |
セッションの有無 | ある(Session使える) | ない(Stateless) |
CSRF保護 | あり | なし |
URLのprefix | なし(素のURL) | 自動で /api が付与される |
レスポンス形式 | HTML、ビューなど | JSONが基本 |
具体例で見る違い
// routes/web.php
Route::get('/dashboard', [DashboardController::class, 'index']);
// routes/api.php
Route::get('/users', [Api\UserController::class, 'index']);
上記の /users は、実際には /api/users にマッピングされます(prefix自動付与)。
一方 /dashboard はそのまま /dashboard で使われます。
CSRFトークン、WebにはあるけどAPIにはない
web.php
ではフォームやPOSTリクエストを送るときに CSRFトークン(@csrf
) が必須。api.php
は CSRF保護が無効になっていて、そもそも「認証のやり方が違う」前提(トークンベース認証など)。
なので、VueやReactとLaravelのAPI連携するときは、api.php
に書いたルートを使うのが自然。
CSRFトークンってなに?
フォームなどを通じた意図しないリクエスト(悪意ある第三者による)を防ぐためのセキュリティ対策です。Laravelでは web.php
に定義されたルートに対してPOSTリクエストを送るとき、CSRFトークンが自動的に必要になります。
設定ファイルで明確に役割が分かれてる
app/Http/Kernel.php
を見ると、以下のように定義されてます
protected $middlewareGroups = [
'web' => [
// セッション、CSRF、クッキーなど
],
'api' => [
'throttle:api',
'bindings',
],
];
つまり、同じルーティング構文でも、どこに書いたかによって内部で動いてる処理が変わります。
同じ Route::get()
という構文でルートを定義していても、それを web.php
に書くか、api.php
に書くかによって、自動で適用されるミドルウェアやリクエストの前提条件が大きく変わります。
たとえば web.php
に書いたルートは、セッションやクッキー、CSRF保護が有効になっており、フォーム送信やログイン後のページなど通常のWebアプリ向けに最適化されています。
一方で api.php
に書いたルートは、ステートレス(状態を持たない)通信を前提としており、CSRFは無効・セッションは使わず、レスポンスもJSONが基本となるため、API連携やモバイルアプリ用のエンドポイントに適しています。
Laravelが裏で自動的に「このルートはWeb用だな」「こっちはAPI用だな」と判別して、それに合った処理の流れを用意してくれているというわけです。
まとめてみるとこう
書く場所 | 自動的に有効になるミドルウェア | 状態 | 想定用途 |
---|---|---|---|
web.php | web グループ(CSRF, session, cookie) | ステートフル | HTMLベースのWebページ |
api.php | api グループ(throttle, bindings) | ステートレス | JSON API、モバイル、SPA通信 |
Laravelルーティングで困ったときのトラブルシュートTips
Laravelのルーティングは基本的にわかりやすい設計になっていますが、変更が反映されない・想定と違う挙動をするといったトラブルに遭遇することもあります。
そんなときは、以下のコマンドやチェック項目を試してみましょう。
ルート一覧を確認する
ルートが正しく登録されているか、一目で確認できるコマンドがこれです。
php artisan route:list
- URI / メソッド / コントローラーの対応関係が一覧表示されます。
- 特に
Route::resource()
を使ったときに、どのルートが自動で作られたか確認するのに超便利。 --name
や--method=POST
などのオプションでフィルタも可能。
キャッシュをクリア
ここに乗ってない場合、実装ミスを除けば大体キャッシュが原因です。
php artisan route:clear
これでルート周りのキャッシュをクリアできます。
これで無理なら
php artisan optimize:clear
これで全キャッシュクリアできます。
おわりに
Laravelのルーティングは、一見シンプルな構文に見えて、
その裏には認証、バリデーション、ミドルウェア、ルートグループ化、さらにはWebとAPIの明確な住み分けなど、実に多くの機能が詰め込まれています。
今回の記事では、ただルートを書くのではなく、「なぜこの書き方なのか」「どこに書くべきなのか」といった設計視点も交えて解説しました。