Help us understand the problem. What is going on with this article?

【Laravel5】FormRequestのバリデーション結果をJSON APIで返す

記事は個人サイトへ移動しました

https://www.luftgarden.jp/blog/1

個人サイト/Qiitaどちらも同じ内容を記載しています(2019/7/15 現在)。

概要

例えば、会員を新規追加するAPIのエンドポイントがあるとします。

[POST] https://example.com/api/users
routes/api.php
Route::resource( 'users', 'Api\UsersController' )->only( ['store'] );

Controllerは以下の状態です。

app/Http/Controllers/Api/UsersController.php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests\StoreUserRequest;
use App\Http\Resources\UserResource;
use App\User;

class UsersController extends Controller
{
    /**
     * 会員追加
     *
     * @param StoreUserRequest $request
     * @return User
     */
    public function store( StoreUserRequest $request )
    {
        return User::create( $request->only( ['name'] ) ); 
    }
}

FormRequestクラスは以下の状態です。

artisan
$ php artisan make:request StoreUserRequest
app/Http/Requests/StoreUserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required',
        ];
    }

    public function messages()
    {
        return [
            'name.required' => 'お名前を入力してください。',
        ];
    }
}

上記APIを叩いた際に「お名前を入力してください」と
JSON形式でエラーメッセージを返却したい場合を考えます。

このままの状態でAPIを叩いても素直にエラーレスポンスが返りません。
(welcomeページのHTMLが返ってきたりする)

原因と対応

バリデーション失敗時にFormRequestクラス内でリダイレクトが発生することが原因のようです。
参考: Laravel5.1.xでAPIを作る際に気になっていたことを調べました - Qiita

バリデーション失敗時にもJSON形式で結果を返すように対応していきます。

Laravel5.4以前

FormRequest::response() をオーバーライドすることで対応可能なようです。

StoreUserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\JsonResponse;  // 追加

class StoreUserRequest extends FormRequest
{
    /**
     * [override] バリデーション失敗時ハンドリング
     *
     * @param array $errors
     * @return JsonResponse
     */
    public function response( array $errors )
    {
        $response = [
            'data'    => [],
            'status'  => 'NG',
            'summary' => 'Failed validation.',
            'errors'  => $errors,
        ];
        return new JsonResponse( $response, 422 );
    }
}

Laravel5.5以降

FormRequest::response() は廃止されているため、代わりに
FormRequest::failedValidation() をオーバーライドすることで対応します。

StoreUserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;  // 追加
use Illuminate\Http\Exceptions\HttpResponseException;  // 追加

class StoreUserRequest extends FormRequest
{
    /**
     * [override] バリデーション失敗時ハンドリング
     *
     * @param Validator $validator
     * @throw HttpResponseException
     * @see FormRequest::failedValidation()
     */
    protected function failedValidation( Validator $validator )
    {
        $response['data']    = [];
        $response['status']  = 'NG';
        $response['summary'] = 'Failed validation.';
        $response['errors']  = $validator->errors()->toArray();

        throw new HttpResponseException(
            response()->json( $response, 422 )
        );
    }
}

実行結果

画像は POSTMAN のキャプチャです。
エンドポイントを叩いてJSONレスポンスが返却されればOKです。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3138343531382f35346430636161392d666263372d613837662d663966642d3231386131626435313536322e706e67.png

API用のリクエストクラスを作成する

APIを作成する場合はレスポンス形式を統一することになると思うので、
下記のような抽象クラスを作成しておいたほうがよいでしょう。
Laravel5.8 FormRequestでバリデーション失敗時にJsonResponseを返す - Qiita

参考記事

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away