第27回: レート制限の実装 — 「1分60回まで」でAPIを守る

章: 第3章: RESTful API設計

APIに制限なし、それは「やり放題」です

認証なしのAPIエンドポイントは、悪意のある大量リクエストや誤ったループ処理によって、サーバーリソースが枯渇する危険があります。結果として、全ユーザーへのサービス品質が低下します。

レート制限を設けることで、1ユーザーあたりのリクエスト数を制御し、APIの安定稼働を守ることができます。

レート制限の実装


<?php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

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

Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::get('/posts', [PostController::class, 'index']);
});

制限なし vs レート制限あり

観点 制限なし レート制限あり
DoS耐性 脆弱 リクエスト数で自動遮断
ユーザーの公平性 一部が大量消費可能 全ユーザーに均等な割当
コスト管理 予測不能 リクエスト数で制御可能
エラー応答 なし 429 Too Many Requests

チェックポイント: $request->user()?->id ?: $request->ip() は認証済みユーザーはIDで、未認証ユーザーはIPで制限します。認証済みユーザーには緩い制限、未認証ユーザーには厳しい制限とする設計も一般的です。

複数の制限ルールを設定する


<?php
RateLimiter::for('api', function (Request $request) {
    // 未認証ユーザー: 1分10回
    if (!$request->user()) {
        return Limit::perMinute(10)->by($request->ip());
    }
    // 管理者: 無制限
    if ($request->user()->isAdmin()) {
        return Limit::none();
    }
    // 一般ユーザー: 1分60回
    return Limit::perMinute(60)->by($request->user()->id);
});

チェックポイント: レート制限を超えた場合は429ステータスと Retry-After ヘッダが自動で返ります。フロントエンドはこのヘッダを見て「X秒後に再試行」のUIを実装できます。

まとめ & 次のステップ

  • RateLimiter::for() でユーザーごと・IPごとのリクエスト制限を設定できる
  • throttle:api ミドルウェアをルートグループに適用するだけで有効になる
  • ユーザー種別ごとに異なる制限ルールを設定して柔軟に管理する

次回はAPIバージョニングを学びます。既存クライアントを壊さずにAPIを進化させる、URLベースのバージョン管理方法です。

Related Articles