メシのタネ

めしのたねになるIT情報配信サイト


FormRequestのポテンシャル、半分も出せてない説


  1. Laravel
  2. FormRequestのポテンシャル、半分も出せてない説

Laravelである程度アプリを作り始めると、自然と出会うのがFormRequestクラスです。
Controllerの中で $request->validate() を書いていた時期から一歩進んで、

public function store(StorePostRequest $request)

のように、Request専用のクラスを引数に使う方法へ移行していく。
「Controllerがすっきりする」「ルールがまとまって書ける」と聞いて、最初は「便利だな」と思ったかもしれません。

ただ——
それ以上、深く使ってみいとは思いませんか?

たとえば、authorize() メソッドに何か書いたことがありますか?
エラーメッセージをカスタマイズしたいとき、messages() メソッドの存在を思い出せますか?
「入力値をちょっと整形してからバリデーションしたいな」と思ったときに、Controllerに戻って書いていませんか?

LaravelのFormRequestは、「Controllerをきれいにするための便利クラス」ではありません。
むしろ、それはLaravelにおける設計の一部
であり、Controllerの責務を軽くするための重要な構成要素です。

この記事では、「FormRequestって実はまだ使いこなせてなかったかも…」というLaravelユーザーに向けて、Requestクラスの本当の役割と、あまり知られていない機能たちを紹介していきます。

あなたのControllerが少しでも「読みづらいな」「また同じバリデーション書いてるな」と感じているなら、この先の話がちょっと役に立つかもしれません。

目次

FormRequestとは? 〜Laravelでの役割〜

LaravelのFormRequestクラスは、一見「バリデーション専用のクラス」と思われがちです。ところが実際には、Controllerと密接に連携し、それぞれの責務を明確に分けるために設計された仕組みとなっています。

🧱 ControllerとFormRequestの役割分担

Controllerの主な役割は、リクエストが来たときに「何をどう処理するか」を決定することです。

Controllerについて書かれた記事はこちら

  • Modelを呼び出してデータを保存したり
  • Viewを返したり
  • APIのレスポンスを組み立てたり

しかし、これらの処理をすべてControllerひとつに詰め込んでしまうと、やがてコードが煩雑になってしまいます。

そこでLaravelは「バリデーションはRequest側(FormRequest)にまとめておいたほうが便利だよね?」という考え方から、FormRequestを導入しました。

⚙️ 自動実行の仕組み:authorize() → rules()

Controllerの引数としてFormRequestを受け取ると、Laravelは以下のステップを自動で実行します:

  1. authorize()
    • このリクエストを処理していいかどうかをチェック(ユーザーの権限など)
  2. rules()
    • 指定したバリデーションルールに沿って入力値を検証

これらはControllerが呼ばれる前に実行されるため、Controllerの中ではすでに「有効な入力データのみを扱える」状態となります。

🗂 FormRequestの主な役割まとめ

役割書く場所内容
ユーザーが実行できるか確認authorize()権限をチェック。Policy未使用でもここでOK
入力ルールの定義rules()例: required, max, emailなど
エラーメッセージの変更messages()バリデーションエラーの文言をカスタマイズ
フィールド名の変更attributes()エラー表示時のフィールド名を調整
入力値の整形・加工prepareForValidation()例: 全角→半角に変換、trimなどの前処理

🧭 設計上の意味:責務の分離

FormRequestの価値は「バリデーションが楽になる」ことだけにとどまりません。大きな視点で見ると、ControllerRequestそれぞれが責任範囲を明確に分担することが重要です。

  • Controller:アプリ全体のフローを管理
  • FormRequest:入力値の妥当性や権限チェックを担う

こうして役割を切り分けることで、コードがシンプルでメンテナンスしやすい形に保たれます。

本当にFormRequestを“使いこなせて”いますか?

FormRequestを導入しているということは、Rulesの扱いも分かっていて、Requestの事前加工、あと加工もできていて、と「使えてはいる」と思いますが、本当に、「使いこなせている」のでしょうか。

Laravelに慣れてくると、php artisan make:request でクラスを作成して、rules() にバリデーションルールを追加するのが自然な流れになります。Controllerがスッキリ見え、なんとなく設計的にも良さそうに感じるでしょう。

でも、ちょっと立ち止まって振り返ってみませんか? 落とし穴にハマっていないか、チェックしてみましょう。

🙈 1. authorize() がひたすら return true;

  • 「ここで何かやる必要あるの?」という雰囲気が漂っている
  • ユーザーの権限チェックができるはずなのに、使われず放置
  • 結果的に、Controller側にif文だらけの認可処理が残ってしまうことも

📎 2. すべてのルールを rules() に詰め込みすぎ

  • 10行超えや複雑なネストでも、とりあえず全部rules()に書くスタイル
  • バリデーションが複雑化して読みづらくなる
  • 配列や条件付きバリデーションで混乱し始めるのもこのパターン

🔤 4. フィールド名がユーザー目線でわかりにくい

  • エラーに「body フィールドが必須です」と出ても、ユーザーにはピンとこない
  • attributes()を使えば「本文が入力されていません」のように、より親切な表示が可能
  • 人間向けの表現に変えないと、「機械翻訳」のようなメッセージに見えてしまう

🧼 5. 入力値の整形はControllerでやっている

  • 全角スペース除去やtrimnullを空文字に変換するなどの前処理
  • 実はprepareForValidation()が使えるけれど、その存在が知られていなかったり敬遠されていたり
  • 結果として、Controllerに「前処理・バリデーション・保存」の三役が混在してしまう

🧪 6. バリデーションのテストが書きづらいと感じている

  • 「Requestのテストってどうやるの?」と検索して終わる
  • 実はRequest単体でもテスト可能な設計なのに、Controller経由でしか確認できないと思い込んでいる
  • 結果として「画面から動作確認する」だけがデフォルトのやり方になってしまう

🧩 まとめ:知っているだけではもったいない

FormRequestは手軽に使えますが、詳細な理解がなくても扱えてしまうため、実装が中途半端になってはいないでしょうか?

Controllerからバリデーションがなくなっただけで満足して、本来FormRequestが持つべき責務を意識できていなければ、とても惜しいです。

次章では、FormRequestの便利な使い方や設計上のメリットをより深く掘り下げます。もう少しだけ、LaravelのFormRequestを一緒により深く理解していきましょう!

FormRequestの“意外と知られていない機能たち

「FormRequest、思ったよりいろいろできるじゃん!」
本章では、そんな感想を引き出すために、FormRequestが持つさまざまな便利機能を紹介します。前章で触れた「使っているつもり」状態から一歩進んで、より洗練された使い方に踏み込みましょう。Laravel公式の機能ながら、見落とされがちだったり、難しそうに思えて敬遠されがちな要素が満載です。

✅ 1. authorize(): リクエスト単位での認可チェック

FormRequestの入口メソッドであるauthorize()は、多くの人がreturn true;と書いたまま放置しがちです。しかし実際には「このリクエストを発行したユーザーが、本当に操作を許可されているか?」を判定できる重要な箇所。

public function authorize()
{
    return $this->user()->id === $this->route('user');
}

たとえば上記のように書けば、ログイン中のユーザーIDとルートパラメータとして渡されたユーザーIDが一致しているかどうかをチェックできます。

💡補足: Laravelにはモデル単位で認可ルールを定義できるPolicy機能もありますが、小規模・ルーティングベースの制御ならauthorize()だけで十分なケースも多いです。

✅ 2. messages(): デフォルトエラー文をやさしく修正

デフォルトのバリデーションエラーは、resources/lang/en/validation.phpja/validation.phpのテンプレートをもとに英語や機械的な文言が返ります。そこで役立つのがmessages()メソッド。

public function messages()
{
    return [
        'title.required' => 'タイトルは必ず入力してください。',
        'body.max' => '本文が長すぎます。もう少し要点を絞りましょう。',
    ];
}

機械的なエラーメッセージから、ユーザーに寄り添った文面に変えてあげるだけで、使い勝手がぐっと良くなります。

✅ 3. attributes(): エラー内の項目名をユーザー向けに

標準設定だと、エラーメッセージ中にtitlebodyなど、フィールド名がそのまま表示されます。ユーザーには伝わりづらい場合もありますよね。そこで使うのがattributes()です。
public function attributes()
{
    return [
        'title' => 'タイトル',
        'body'  => '本文',
    ];
}

これだけでController側に前処理を任せる必要がなくなります。入力に対する修正や補正の責務をFormRequestに集約できるのは大きなメリットです。

✅ 4. prepareForValidation(): 入力データの前処理

ユーザー入力がいつも整った状態とは限りません。全角スペース、不要な改行、数値が文字列で送信されるなど、さまざま。そうした“惜しい”データをバリデーション前に整形できるのがprepareForValidation()です。

protected function prepareForValidation()
{
    $this->merge([
        'title' => trim($this->title),
    ]);
}

✅ 5. validated(): バリデーション済みデータのみを取得

Controllerで$request->all()$request->input()を使うと、不要なデータが混在する可能性があります。代わりに利用すべきなのがvalidated()メソッドです。

$data = $request->validated();

これはFormRequestのrules()を通過した安全なデータだけを取り出してくれます。

🎭 Before / Afterで比較

Before:Controllerですべて頑張るコード

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|max:255',
        'body'  => 'required',
    ]);

    $title = trim($validated['title']);

    Post::create([
        'title' => $title,
        'body'  => $validated['body'],
    ]);
}

After:FormRequestを活用した大人のスタイル

// Controller
public function store(StorePostRequest $request)
{
    Post::create($request->validated());
}

// StorePostRequest
protected function prepareForValidation()
{
    $this->merge([
        'title' => trim($this->title),
    ]);
}

public function rules()
{
    return [
        'title' => 'required|max:255',
        'body'  => 'required',
    ];
}

🧩 小さな工夫が、設計全体を引き締める

紹介したメソッドはどれも「知ってたら役立つ」ものですが、実際に活用するとControllerの責務が一段と軽くなり、コードの見通しも大幅に向上します。

  • 認可 → authorize()
  • 入力検証 → rules()
  • エラーメッセージ → messages(), attributes()
  • 入力データの整形 → prepareForValidation()
  • 安全なデータ取り出し → validated()

FormRequestがこうした入口処理を一手に引き受けてくれることで、Laravelアプリ全体の構成が整理され、よりメンテナンスしやすい設計へと進化していきます。

FormRequestがコードベース全体に与える設計的メリット

これまで、FormRequestが持っている便利な機能や、その具体的な使い方をいくつか見てきました。けれど、FormRequestの本当の価値は「Controllerのコードがちょっと短くなる」とか「エラーメッセージが丁寧になる」といった見た目の変化だけではありません。

使いこなすことで、プロジェクト全体の設計がひとつ上の段階へ整理されていく。
それこそが、FormRequestの真のポテンシャルです。

✅ 1. Controllerが「流れの指揮官」らしくなる

FormRequestを使うと、Controllerがバリデーションから解放され、
「どの処理を、どの順序で呼び出すか」だけに集中できるようになります。

これは一見地味ですが、Controllerを「処理を書く場所」ではなく「処理の流れを構成する場所」として整理できるようになる、という意味です。

✍️ Before:

public function store(Request $request)
{
    $request->validate([...]);
    $data = trim($request->input('title'));
    $post = Post::create($data);
}

✨ After:

public function store(StorePostRequest $request)
{
    $post = Post::create($request->validated());
}

短くなるだけでなく、「このメソッドは何をしているか」が一目でわかるようになります。

✅ 2. 入力チェックが“独立した責任”として完結する

Controllerでのバリデーションは、「入力値の整合性チェック」と「アプリの処理」が混在します。
FormRequestに任せることで、「このクラスは正しい入力だけを保証する」という責任が明確に定義できるようになります。

この責任の明示は、あとから仕様が変わったときにとても効いてきます。

  • 入力ルールの修正が一箇所にまとまる
  • 他のルートやControllerからも再利用できる
  • どこをテストすればいいかが分かりやすい

✅ 3. テストが“設計に寄り添った形”で書ける

FormRequestは、そのままユニットテストの対象になります。

public function test_タイトルが必須チェックが機能すること()
{
    // given
    $request = new StorePostRequest();
    $expected = false;
    // when
    $actual = $request->passesValidation(['title' => '']);
    // then
    $this->assertEquals($expected,$actual);
}

これにより、「バリデーションだけを対象にしたテスト」が可能になります。
つまり、Controllerやデータベースに依存しない軽量なテスト構成が作れるようになるので

✅ 4. 保守性と拡張性が、じわじわ上がる

今は小さいControllerでも、機能が増えるたびにやることは増えていきます。

  • 入力が10項目になった
  • ユーザーの権限条件が追加された
  • バリデーションの内容が複雑になった

こうしたとき、FormRequestにロジックが分離されていることで、Controller側の影響を最小限に保つことができるので、要求が増えた分もテストがしやすくなります
結果として、改修コストが下がり、バグの入り込む余地も減ります。

🧩 まとめ:FormRequestは「ちょっと便利な道具」ではなく「設計の一員」

Controllerにとって、FormRequestは単なるバリデーションヘルパーではありません。
それは「責任を預ける相棒」であり、プロジェクトの設計を支える一部の構造です。

便利だから使う、から一歩進んで、設計のために使う。

この意識の転換ができると、Laravelの開発体験はより快適で、より見通しの良いものになります。

段階的に進めるFormRequest — コードの進化は少しずつ

ここまで読み進めたあなたなら、「FormRequestが単なる入力チェックじゃない」ことをすでに感じ取っているでしょう。Laravelの設計においても重要な役割を持つクラスだという点を既に理解できているのではないでしょうか。

🪨 すぐに全部移行しなくても大丈夫

  • 「今さら既存のプロジェクト全部をFormRequestに置き換えるのは無理…」
  • 「少しずつ移行したいけど、どこから始めればいいかわからない…」

そんな心配はいりません。FormRequestはあくまで「使わなきゃいけない」ものではありません。必要に応じて、柔軟に取り入れれていきましょう。

🌱 違和感を覚えたときこそ、FormRequestの出番

  • Controllerが肥大化している
  • 大量のController一つ一つにバリデーションルールのコピーが散らばっている
  • 認可や前処理などの責務が混ざってきた

こうした、気になる場面に遭遇したら、「FormRequestにしたい・・・」と考えてみる。それだけでも、Laravelアプリのコード構成を大きく見直すきっかけになります。

🧭 設計は一度きりでは終わらない

Laravelの開発は、アプリが成長し、仕様やチーム体制が変わるたびに、何度も設計を見直す機会が訪れます。「今よりも良い構造にするには?」を常に問いかけ続けるのは必然の流れかも知れません。
FormRequestも改修する流れになった時、リファクタリングの大事な選択肢。実装したい時に実装する程度の距離感で付き合えば、ストレスなく実装できるのではないでしょうか。

🧩 最後に:育てるのはあなた

Laravelを使ってると、便利だなと思うことは多いです。しかし、そこでただ利用するだけでなく自分なりに設計意図を取り込むと、より便利に、道具として活かせるようになります。
「Controllerに書いていた処理を、ちょっと分けてみよう」という小さな実践が、いつの間にかコード全体の見通しを良くしてくれます。

「使える機能」を「育てて活かす機能」に変える。
その気づきがあれば、Laravelは簡単に便利機能が実装できるだけのフレームワークではなく、あなたが“育てていけるフレームワークへと姿を変えるでしょう。

これで「FormRequestを本当は活かしきれていない説」はひとまずおしまい。
あなたのControllerとRequestが、これからより快適に住み分けられますように。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.

若い頃、「仕事中にハマったこと」や「誰かに共有したい技術的な気づき」をアウトプットしたくてブログを始めましたが、勢い任せでよく分からない記事を大量生産し、あえなく飽きて終了。

改めて今、キャリア15年分の経験や知識が、これからITエンジニアを目指す方や、同じような課題で悩んでいる現役エンジニアの「メシのタネ」になるような記事を残したいと思っています。
※過去の記事は見ると精神が崩壊するため、そっとしておいてください。

🛠 経歴という名の珍道中:
文系Fラン → 広告営業 → Web営業 → 通信営業 → Web進行 → 出版 → Web媒体運用 → ソフトウェアハウス → SES → フリーランス

専門教育も受けず、転職歴も多数。履歴書はまるで時系列の事故記録のようですが、試行錯誤を重ね、なんとかエンジニアとして食べています。

このブログでは、そんな「履歴書クラッシャー型エンジニア」が送る、
名古屋一敷居の低い、実務に役立つ技術ブログを目指します。

Laravel
Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?New!!
Laravel
Eloquentのリレーション徹底解説New!!
Laravel
Eloquentは知ってる。でも“理解してる”って言えるのか?New!!
Laravel
FormRequestのポテンシャル、半分も出せてない説New!!
Laravel
Laravel Controllerの“万能感”、そこに幸せはあるのかい?New!!
API
RESTってつまり何?Webエンジニアが悩まないためのAPI設計入門