章: 第3章: RESTful API設計
バリデーションをコントローラに直書きしていませんか?
if (empty($request->title)) { return error(); } をコントローラに書き続けると、バリデーションロジックが散らばり、テストも困難になります。複数のエンドポイントで同じルールが重複し、変更のたびに複数箇所を修正しなければなりません。
LaravelのForm Requestクラスを使えば、バリデーションロジックを専用クラスに集約し、コントローラはバリデーション済みのデータだけを受け取れます。
リクエストバリデーションの実装
<?php
class StorePostRequest extends FormRequest {
public function authorize(): bool { return true; }
public function rules(): array {
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string'],
'tags' => ['array'],
'tags.*' => ['string', 'max:30'],
];
}
public function messages(): array {
return ['title.required' => 'タイトルは必須です'];
}
}
コントローラ直書き vs Form Request
| 観点 | コントローラ直書き | Form Requestクラス |
| 責務の分離 | コントローラが肥大化 | バリデーションが専用クラスに |
| 再利用 | 同じルールを複数箇所に書く | クラスを使い回せる |
| テスト | コントローラごとにテスト | Form Requestを単体テスト |
| エラー応答 | 手動でエラーレスポンスを組む | 422を自動で返す |
チェックポイント:
authorize()はリクエストの認可チェックです。return trueだと全員許可ですが、実際は$this->user()->can('create', Post::class)のようにポリシーと連携させましょう。
コントローラでの使い方
<?php
class PostController extends Controller {
// Form Requestをタイプヒントするだけでバリデーションが自動実行される
public function store(StorePostRequest $request): JsonResponse {
// ここに来た時点でバリデーション済み
$post = Post::create($request->validated());
return response()->json(['success' => true, 'data' => $post], 201);
}
}
チェックポイント:
$request->validated()はバリデーション済みのフィールドのみを返します。$request->all()を使うと未バリデーションのデータが混入するリスクがあります。
まとめ & 次のステップ
- Form Requestはバリデーションロジックを専用クラスに分離する
- コントローラは
$request->validated()でバリデーション済みデータだけを受け取る authorize()でポリシーとの連携が可能
次回は認証付きAPI(APIトークン)を学びます。LaravelのSanctumを使ってトークンベースのAPI認証を実装する方法です。