本文へ移動
Laravel Tips

ルーティング

URL とそれを受け持つ処理を結びつけるルーティングの書き方を説明します。パラメータ・名前・グループ・モデルの自動取得・回数の制限まで引けます。

ルーティングは、「この URL に来たら、この処理を動かす」と決めることです。お店でいえば、お客さんの用件を聞いて担当の窓口へ案内する受付係の仕事にあたります。Laravel のルート(URL と処理の組)は、いちばん簡単な形だと、URL とクロージャ(名前のない関数)を書くだけで作れます。

いちばん基本のルート#

php
use Illuminate\Support\Facades\Route;

Route::get('/greeting', function () {
    return 'Hello World';
});

/greeting を開くと、Hello World と表示されます。

ルートを書くファイル#

ルートは routes フォルダの中のファイルに書きます。bootstrap/app.php の設定で、Laravel が自動で読み込みます。画面用のルートは routes/web.php に書きます。ここに書いたルートには web というミドルウェアのグループ(リクエストの前に間に入る処理のまとまり)がかかります。そのおかげで、セッション(同じ人のアクセスをまたいで情報を覚えておくしくみ)や CSRF 対策(なりすましの送信を防ぐしくみ)が使えます。

はじめは routes/web.php に書けば足ります。たとえば、次のルートは http://example.com/user をブラウザで開くと動きます。

php
use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);

API 用のルート#

ログイン状態を持たない API(ほかのプログラムからデータをやり取りする窓口)も作るなら、次の Artisan コマンド(php artisan で動かす Laravel のコマンド)で、API 用のルートを使えるようにします。

bash
php artisan install:api

このコマンドは Laravel Sanctum(API の利用者を確かめる道具)を入れ、routes/api.php を作ります。

php
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

だれでも使ってよいルートなら、auth:sanctum は付けなくてかまいません。

routes/api.php のルートは、api ミドルウェアグループがかかり、ログイン状態を覚えません。URL の頭には自動で /api が付くので、1本ずつ書く必要はありません。この頭の部分は bootstrap/app.php で変えられます。

php
->withRouting(
    api: __DIR__.'/../routes/api.php',
    apiPrefix: 'api/admin',
    // ...
)

使えるルーターのメソッド#

どの HTTP メソッド(リクエストの種類)にも対応するルートを書けます。

php
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
メソッド 説明
Route::get GET(ページを見る)に答える
Route::post POST(データを送る)に答える
Route::put PUT(まるごと更新する)に答える
Route::patch PATCH(一部を更新する)に答える
Route::delete DELETE(消す)に答える
Route::options OPTIONS(使える種類をたずねる)に答える
Route::match 指定した複数のメソッドに答える
Route::any すべてのメソッドに答える

複数のメソッドに答えたいときは match、全部に答えたいときは any を使います。

php
Route::match(['get', 'post'], '/', function () {
    // ...
});

Route::any('/', function () {
    // ...
});

補足

同じ URL のルートを複数書くときは、get・post・put・patch・delete・options を先に、any・match・redirect を後に書きます。そうしないと、リクエストが正しいルートに結びつきません。

必要なものを受け取る(依存性の注入)#

ルートの関数の引数に型を書くと、サービスコンテナ(クラスを作って渡してくれる道具箱)が、必要なものを自動で渡してくれます。これを依存性の注入といいます。たとえば Request を書けば、いまのリクエストが渡されます。

php
use Illuminate\Http\Request;

Route::get('/users', function (Request $request) {
    // ...
});

CSRF 対策#

web のルートで POST・PUT・PATCH・DELETE に送るフォームには、CSRF トークン(なりすましを防ぐ合言葉)の欄が要ります。ないと、リクエストは受け付けられません。くわしくは CSRF 対策を見てください。

blade
<form method="POST" action="/profile">
    @csrf
    ...
</form>

転送するルート(リダイレクト)#

別の URL へ転送するだけなら、Route::redirect が近道です。コントローラーを作らなくて済みます。

php
Route::redirect('/here', '/there');

ふつうは 302(一時的な転送)を返します。3つ目の引数で変えられます。

php
Route::redirect('/here', '/there', 301);

301(ずっとそこへ移った、という転送)なら Route::permanentRedirect でも書けます。

php
Route::permanentRedirect('/here', '/there');

注意

転送のルートでルートパラメータ(URL の一部を受け取るしくみ)を使うときは、destination と status は Laravel が使うので、名前にできません。

ビューを返すだけのルート#

ビュー(画面の見た目を書いたファイル)を返すだけなら、Route::view が使えます。1つ目が URL、2つ目がビューの名前、3つ目(省略できます)がビューへ渡すデータです。

php
Route::view('/welcome', 'welcome');

Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

注意

ビューのルートでルートパラメータを使うときは、view・data・status・headers は名前にできません。

ルートの一覧を見る#

route:list コマンドで、アプリにあるルートを一覧で見られます。

bash
php artisan route:list

ふつうはミドルウェアが出ません。-v を付けると、ミドルウェアとグループの名前が出ます。

bash
php artisan route:list -v

# ミドルウェアのグループを広げて見る
php artisan route:list -vv
オプション 説明
-v ルートにかかるミドルウェアとグループの名前も出す
-vv グループを広げて、中のミドルウェアまで出す
--path=api URL に指定の文字を含むルートだけ出す
--except-vendor パッケージが作ったルートを隠す
--only-vendor パッケージが作ったルートだけ出す
bash
php artisan route:list --path=api
php artisan route:list --except-vendor
php artisan route:list --only-vendor

ルートの読み込み方を変える#

ルートは、ふつう bootstrap/app.php が読み込みます。

php
<?php

use Illuminate\Foundation\Application;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )->create();

ルートの一部を別のファイルに分けたいときは、withRouting に then のクロージャを渡して、足したいルートを登録します。

php
use Illuminate\Support\Facades\Route;

->withRouting(
    web: __DIR__.'/../routes/web.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
    then: function () {
        Route::middleware('api')
            ->prefix('webhooks')
            ->name('webhooks.')
            ->group(base_path('routes/webhooks.php'));
    },
)

ルートの登録を全部自分でしたいときは、using のクロージャを渡します。すると Laravel は HTTP のルートを1つも登録しないので、すべて自分で書きます。

php
use Illuminate\Support\Facades\Route;

->withRouting(
    commands: __DIR__.'/../routes/console.php',
    using: function () {
        Route::middleware('api')
            ->prefix('api')
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->group(base_path('routes/web.php'));
    },
)

ルートパラメータ(URL の一部を受け取る)#

必ず要るパラメータ#

URL の一部を取り出して使いたいときは、{} で囲んだルートパラメータを書きます。たとえば、URL の中のユーザー番号を受け取れます。

php
Route::get('/user/{id}', function (string $id) {
    return 'User '.$id;
});

いくつでも書けます。

php
Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {
    // ...
});

パラメータの名前は、英字と _ で作ります。関数の引数には、名前ではなく並んだ順で渡されます。なので、引数の名前は何でもかまいません。

パラメータと依存性の注入#

道具箱から渡してほしいものがあるときは、それを先に書き、ルートパラメータを後ろに並べます。

php
use Illuminate\Http\Request;

Route::get('/user/{id}', function (Request $request, string $id) {
    return 'User '.$id;
});

あってもなくてもよいパラメータ#

名前のあとに ? を付けると、URL にその部分がなくてもよくなります。そのとき、関数の引数には初期値を書きます。

php
Route::get('/user/{name?}', function (?string $name = null) {
    return $name;
});

Route::get('/user/{name?}', function (?string $name = 'John') {
    return $name;
});

正規表現で形を決める#

where メソッドで、パラメータの形を正規表現(文字の並びのパターンを書く決まり)で縛れます。

php
Route::get('/user/{name}', function (string $name) {
    // ...
})->where('name', '[A-Za-z]+');

Route::get('/user/{id}', function (string $id) {
    // ...
})->where('id', '[0-9]+');

Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

よく使う形には、近道のメソッドがあります。

メソッド 説明
whereNumber 数字だけ
whereAlpha 英字だけ
whereAlphaNumeric 英字と数字だけ
whereUuid UUID の形だけ
whereUlid ULID の形だけ
whereIn 決めた値のどれかだけ
php
Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->whereNumber('id')->whereAlpha('name');

Route::get('/user/{name}', function (string $name) {
    // ...
})->whereAlphaNumeric('name');

Route::get('/user/{id}', function (string $id) {
    // ...
})->whereUuid('id');

Route::get('/user/{id}', function (string $id) {
    // ...
})->whereUlid('id');

Route::get('/category/{category}', function (string $category) {
    // ...
})->whereIn('category', ['movie', 'song', 'painting']);

Route::get('/category/{category}', function (string $category) {
    // ...
})->whereIn('category', CategoryEnum::cases());

形に合わない URL が来たときは、404(ページが見つからない)が返ります。

どのルートにも同じ決まりを付ける#

同じ名前のパラメータを、いつも同じ形に縛りたいときは pattern を使います。App\Providers\AppServiceProvider(アプリの起動のときに設定を書くクラス)の boot メソッドに書きます。

php
use Illuminate\Support\Facades\Route;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}

こうすると、{id} という名前のパラメータを持つルートすべてに、この決まりがかかります。

php
Route::get('/user/{id}', function (string $id) {
    // {id} が数字のときだけ動く
});

スラッシュを含む値#

ルートパラメータの値には、/ 以外のどんな文字も使えます。/ を含めたいときは、where で正規表現を書いて許します。

php
Route::get('/search/{search}', function (string $search) {
    return $search;
})->where('search', '.*');

注意

エンコードした /(URL の中で %2F と書きかえた /)を含められるのは、ルートのいちばん最後の部分だけです。

名前を付けたルート#

ルートに名前を付けておくと、URL や転送先を、名前から作れます。name メソッドをつなぎます。

php
Route::get('/user/profile', function () {
    // ...
})->name('profile');

コントローラーのルートにも付けられます。

php
Route::get(
    '/user/profile',
    [UserProfileController::class, 'show']
)->name('profile');

注意

ルートの名前は、ほかと重ならないようにします。

名前から URL を作る#

名前を付けたら、route と redirect のヘルパー関数で、名前から URL や転送を作れます。URL を直接書かないので、あとで URL を変えても直す場所が少なく済みます。

php
// URL を作る
$url = route('profile');

// 転送を作る
return redirect()->route('profile');

return to_route('profile');

ルートにパラメータがあるときは、route の2つ目の引数に配列で渡すと、正しい位置に入ります。

php
Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');

$url = route('profile', ['id' => 1]);

配列に余分な値を入れると、クエリ文字列(URL の ? 以降)として付きます。

php
Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']);

// http://example.com/user/1/profile?photos=yes

補足

言語の設定のように、リクエスト全体で使う URL パラメータの初期値を決めたいときは、URL::defaults メソッドを使います。くわしくは URL を作るを見てください。

いまのルートを調べる#

いまのリクエストが、ある名前のルートに来たものか調べるには、ルートの named メソッドを使います。たとえば、ミドルウェアの中で調べられます。

php
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Handle an incoming request.
 *
 * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
 */
public function handle(Request $request, Closure $next): Response
{
    if ($request->route()->named('profile')) {
        // ...
    }

    return $next($request);
}

ルートグループ#

ルートグループを使うと、たくさんのルートに同じ設定(ミドルウェアなど)を、1つずつ書かずにまとめて付けられます。

グループの中にグループを入れると、設定は外側と内側が合わさります。ミドルウェアと where の条件は足し合わされ、名前と URL の頭は後ろへつながります。名前空間(クラスの置き場所を表す名前)の区切りや、URL のスラッシュは、必要なところに自動で入ります。

ミドルウェアをまとめて付ける#

グループの前で middleware メソッドを呼びます。ミドルウェアは、配列に書いた順に動きます。

php
Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // first と second のミドルウェアが使われる
    });

    Route::get('/user/profile', function () {
        // first と second のミドルウェアが使われる
    });
});

コントローラーをまとめる#

同じコントローラーを使うルートが並ぶなら、controller メソッドでまとめます。各ルートには、動かすメソッドの名前だけを書きます。

php
use App\Http\Controllers\OrderController;

Route::controller(OrderController::class)->group(function () {
    Route::get('/orders/{id}', 'show');
    Route::post('/orders', 'store');
});

サブドメインで分ける#

サブドメイン(example.com の前に付く名前。shop.example.com の shop)ごとにルートを分けられます。サブドメインにもルートパラメータが使え、その部分を取り出せます。グループの前で domain メソッドを呼びます。

php
Route::domain('{account}.example.com')->group(function () {
    Route::get('/user/{id}', function (string $account, string $id) {
        // ...
    });
});

URL の頭をそろえる#

prefix メソッドで、グループ内のすべてのルートの URL の頭に、同じ文字を付けられます。

php
Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        // "/admin/users" の URL に当たる
    });
});

ルートの名前の頭をそろえる#

name メソッドで、グループ内のすべてのルートの名前の頭に、同じ文字を付けられます。書いた文字がそのまま頭に付くので、最後の . も自分で書きます。

php
Route::name('admin.')->group(function () {
    Route::get('/users', function () {
        // このルートの名前は "admin.users" になる
    })->name('users');
});

ルートモデルバインディング#

ルートに ID が来ると、その ID のデータをデータベースから取り出す処理をよく書きます。ルートモデルバインディングを使うと、ID ではなく、その ID に当たるモデル(データベースの表を PHP から扱いやすくしたクラス)を、そのまま受け取れます。

自動で結びつける(暗黙の結合)#

関数の引数に Eloquent(Laravel のモデルのしくみ)のモデルの型を書き、変数の名前をルートパラメータの名前に合わせます。すると、Laravel が自動でそのモデルを探して渡します。

php
use App\Models\User;

Route::get('/users/{user}', function (User $user) {
    return $user->email;
});

$user に App\Models\User の型が付き、名前が {user} と同じなので、URL の値と同じ ID を持つユーザーが渡されます。見つからなければ、自動で 404 が返ります。

コントローラーのメソッドでも同じです。

php
use App\Http\Controllers\UserController;
use App\Models\User;

// ルートの書き方
Route::get('/users/{user}', [UserController::class, 'show']);

// コントローラーのメソッドの書き方
public function show(User $user)
{
    return view('user.profile', ['user' => $user]);
}

論理削除したモデル#

論理削除(消したことにして、データは残す方法)したモデルは、ふつう取り出されません。取り出したいときは、ルートに withTrashed をつなぎます。

php
use App\Models\User;

Route::get('/users/{user}', function (User $user) {
    return $user->email;
})->withTrashed();

id 以外の列で探す#

id 以外の列で探したいときは、パラメータの定義に列の名前を書きます。

php
use App\Models\Post;

Route::get('/posts/{post:slug}', function (Post $post) {
    return $post;
});

そのモデルをいつも別の列で探したいときは、モデルに RouteKey の属性(PHP のクラスの前に書く印)を付けます。

php
use Illuminate\Database\Eloquent\Attributes\RouteKey;
use Illuminate\Database\Eloquent\Model;

#[RouteKey('slug')]
class Post extends Model
{
    // ...
}

親の中から探す(スコープ)#

1つのルートに複数のモデルがあるとき、2つ目を「1つ目の子」に限りたいことがあります。たとえば、あるユーザーの投稿を、スラッグ(URL に使う名前)で探すルートです。

php
use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

入れ子(親の中に子がある形)のパラメータに id 以外の列を指定すると、Laravel は親の中から子を探します。このとき、親のモデルに、パラメータ名の複数形のリレーション(表どうしのつながり)がある、と見なします。この例なら、User に posts というリレーションがあるはずです。

列を指定しなくても、子を親の中から探したいときは、scopeBindings を呼びます。

php
use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
})->scopeBindings();

グループ全体に付けることもできます。

php
Route::scopeBindings()->group(function () {
    Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
        return $post;
    });
});

逆に、親の中から探さないと決めるには withoutScopedBindings を呼びます。

php
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
})->withoutScopedBindings();

見つからないときの動きを変える#

見つからないときは、ふつう 404 になります。missing メソッドにクロージャを渡すと、その場合の動きを変えられます。

php
use App\Http\Controllers\LocationsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
    ->name('locations.view')
    ->missing(function (Request $request) {
        return Redirect::route('locations.index');
    });

Enum で結びつける#

PHP 8.1 から Enum(決めた値だけを持てるクラス)が使えます。文字を値に持つ Enum を型に書くと、URL の値がその Enum の値のどれかのときだけ、ルートが動きます。ちがえば自動で 404 です。

php
<?php

namespace App\Enums;

enum Category: string
{
    case Fruits = 'fruits';
    case People = 'people';
}

次のルートは、{category} が fruits か people のときだけ動きます。

php
use App\Enums\Category;
use Illuminate\Support\Facades\Route;

Route::get('/categories/{category}', function (Category $category) {
    return $category->value;
});

自分で結びつけを決める(明示的な結合)#

名前の決まりに頼らず、パラメータとモデルの組み合わせを自分で決めることもできます。AppServiceProvider の boot メソッドの最初に、ルーターの model メソッドを書きます。

php
use App\Models\User;
use Illuminate\Support\Facades\Route;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Route::model('user', User::class);
}

あとは {user} を持つルートを書きます。

php
use App\Models\User;

Route::get('/users/{user}', function (User $user) {
    // ...
});

{user} はすべて App\Models\User に結びついたので、users/1 へのリクエストには、ID が 1 のユーザーが渡されます。見つからなければ、自動で 404 が返ります。

探し方を自分で書く#

モデルの探し方そのものを変えたいときは、Route::bind を使います。クロージャは URL の値を受け取り、渡したいモデルを返します。これも AppServiceProvider の boot メソッドに書きます。

php
use App\Models\User;
use Illuminate\Support\Facades\Route;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Route::bind('user', function (string $value) {
        return User::where('name', $value)->firstOrFail();
    });
}

別の方法として、Eloquent モデルの resolveRouteBinding メソッドを上書きできます。URL の値を受け取り、渡したいモデルを返します。

php
/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    return $this->where('name', $value)->firstOrFail();
}

親の中から子を探す(スコープ)ルートでは、子を探すのに resolveChildRouteBinding メソッドが使われます。

php
/**
 * Retrieve the child model for a bound value.
 *
 * @param  string  $childType
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveChildRouteBinding($childType, $value, $field)
{
    return parent::resolveChildRouteBinding($childType, $value, $field);
}

どれにも当たらなかったとき(フォールバック)#

Route::fallback で、ほかのどのルートにも当たらなかったときに動くルートを決められます。ふつう、どのルートにも当たらなかったリクエストには、エラーを扱う処理が自動で「404」のページを返します。ただ、fallback はふつう routes/web.php に書くので、web ミドルウェアグループの処理もすべてかかります。必要ならミドルウェアも足せます。

php
Route::fallback(function () {
    // ...
});

回数を制限する(レート制限)#

制限のルールを作る#

Laravel には、ルート(またはルートのグループ)へのアクセスの数を制限するしくみがあります。まず、制限のルールを作ります。

ルールは App\Providers\AppServiceProvider の boot メソッドに書きます。

php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}

RateLimiter ファサード(クラス名と :: で呼べる窓口)の for メソッドに、ルールの名前と、制限を返すクロージャを渡します。制限は Illuminate\Cache\RateLimiting\Limit クラスで表します。このクラスには、制限を組み立てるためのメソッドがそろっています。ルールの名前は好きな文字でかまいません。

php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(1000);
    });
}

制限を超えると、Laravel は自動で 429 のエラーを返します。返す内容を自分で決めたいときは response メソッドを使います。

php
RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000)->response(function (Request $request, array $headers) {
        return response('Custom response...', 429, $headers);
    });
});

クロージャはリクエストを受け取るので、リクエストやログインしている人によって、制限を変えられます。

php
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()?->vipCustomer()
        ? Limit::none()
        : Limit::perHour(10);
});

人ごとに制限を分ける#

by メソッドを使うと、好きな値ごとに別々に数えられます。たとえば、IP アドレス(ネットワーク上の住所のようなもの)ごとに、1分に100回までにできます。

php
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
        ? Limit::none()
        : Limit::perMinute(100)->by($request->ip());
});

別の例です。ログインしている人は、ユーザー ID ごとに1分に100回まで、ログインしていない人は、IP アドレスごとに1分に10回までにします。

php
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()
        ? Limit::perMinute(100)->by($request->user()->id)
        : Limit::perMinute(10)->by($request->ip());
});

制限を2つ以上かける#

制限の配列を返すと、並んだ順に、1つずつ調べられます。

php
RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(500),
        Limit::perMinute(3)->by($request->input('email')),
    ];
});

同じ値で分けた制限を複数置くときは、by の値がそれぞれ別になるようにします。値の頭に印を付けるのが簡単です。

php
RateLimiter::for('uploads', function (Request $request) {
    return [
        Limit::perMinute(10)->by('minute:'.$request->user()->id),
        Limit::perDay(1000)->by('day:'.$request->user()->id),
    ];
});

返した結果で数える#

after メソッドを使うと、リクエストではなく、返したレスポンスを見て、数えるかどうかを決められます。入力のエラーや 404 など、特定の結果だけ数えたいときに便利です。

after には、レスポンスを受け取るクロージャを渡します。数えるなら true、数えないなら false を返します。たとえば、404 が続く回数を制限すれば、ID を片っぱしから試して探られるのを防げます。また、入力のチェックで止められてやり直した分は数えず、成功した操作だけを制限することもできます。

php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Symfony\Component\HttpFoundation\Response;

RateLimiter::for('resource-not-found', function (Request $request) {
    return Limit::perMinute(10)
        ->by($request->user()?->id ?: $request->ip())
        ->after(function (Response $response) {
            // 404 のレスポンスだけを数える(IDの総当たりを防ぐため)
            return $response->status() === 404;
        });
});

Limit で使うメソッドを、ここで出てきたものだけまとめます。

メソッド 説明
Limit::perMinute 1分あたりの回数で制限する
Limit::perHour 1時間あたりの回数で制限する
Limit::perDay 1日あたりの回数で制限する
Limit::none 制限しない
by 数える単位(人・IP など)を決める
response 超えたときに返す内容を決める
after 返したレスポンスを見て、数えるか決める

ルートに制限を付ける#

ルールは、throttle ミドルウェアで、ルートやグループに付けます。throttle: の後ろにルールの名前を書きます。

php
Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        // ...
    });

    Route::post('/video', function () {
        // ...
    });
});

Redis で数える#

throttle ミドルウェアの中身は、ふつう Illuminate\Routing\Middleware\ThrottleRequests クラスです。キャッシュ(一度作った結果を取っておくしくみ)に Redis(高速なデータの保存先)を使っているなら、回数を数えるのも Redis に任せられます。bootstrap/app.php で throttleWithRedis メソッドを呼ぶと、throttle が Illuminate\Routing\Middleware\ThrottleRequestsWithRedis になります。

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->throttleWithRedis();
    // ...
})

フォームで PUT・PATCH・DELETE を使う#

HTML のフォームは、PUT・PATCH・DELETE で送れません。そのため、フォームから呼ぶこれらのルートには、_method という隠し入力欄を足します。この欄の値が、HTTP メソッドとして使われます。

blade
<form action="/example" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

Blade の @method ディレクティブ(@ で始まる命令)を使うと、_method の欄を作れます。

blade
<form action="/example" method="POST">
    @method('PUT')
    @csrf
</form>

いまのルートの情報を取り出す#

Route ファサードの current・currentRouteName・currentRouteAction で、いまのリクエストを受け持つルートの情報が取れます。

メソッド 説明
Route::current ルートそのもの(Illuminate\Routing\Route)を返す
Route::currentRouteName ルートの名前を返す
Route::currentRouteAction ルートが動かす処理(コントローラーとメソッドなど)を返す
php
use Illuminate\Support\Facades\Route;

$route = Route::current(); // Illuminate\Routing\Route
$name = Route::currentRouteName(); // string
$action = Route::currentRouteAction(); // string

使えるメソッドの全部は、Laravel の API ドキュメントの、Route ファサードの元のクラスと、ルートのクラスの説明で調べられます。

CORS(ほかのサイトからの呼び出しを許す決まり)#

CORS は、あるサイトの JavaScript が、別のドメインのサーバーへリクエストしてよいかを決める、ブラウザの決まりです。Laravel は、CORS をたずねる OPTIONS リクエストに、設定した値で自動で答えます。この仕事は、すべてのリクエストにかかるミドルウェアの HandleCors が受け持ちます。これは最初から入っています。

設定を変えたいときは、config:publish コマンドで cors の設定ファイルを取り出します。

bash
php artisan config:publish cors

config フォルダに cors.php ができます。

補足

CORS と、その HTTP ヘッダーについては、MDN の CORS の説明に詳しく書かれています。

ルートのキャッシュ#

本番へ公開するときは、ルートのキャッシュ(作った結果を取っておくこと)を使います。すべてのルートを登録する時間が、ぐっと短くなります。route:cache コマンドで作ります。

bash
php artisan route:cache

そのあとは、キャッシュされたルートのファイルが、リクエストのたびに読み込まれます。ルートを足したら、キャッシュを作り直します。そのため、route:cache は公開(デプロイ)のときだけ実行します。

キャッシュは route:clear で消せます。

bash
php artisan route:clear

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧