LoginSignup
116
100

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-02-15

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

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

概要

例えば、会員を新規追加する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

参考記事

116
100
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
116
100