LoginSignup
14
18

More than 5 years have passed since last update.

Laravel5.7でAPIのJSONエラーメッセージをカスタマイズしたい

Posted at

APIのバリデーションも(フロントと同様)FormRequestで行いたい場合の対応。

やりたいこと

  • エラー時のJSONメッセージのカスタマイズ(statusとかの追加)したい
  • URLパラメータ(/users/{id}/{password})もバリデーションしたい

JSONのカスタマイズのイメージは

{
    "status": "NG",
    "date": "2018-10-24",
    "message": "password must be at least 4 chars。"
}

こな感じ。
status入れたり、エラーメッセージはバリデーション機能が返すものを利用するけどkeyは変えたいとか。

実装

FormRequestを利用していろいろ記述する。

ルーティング

api.phpに下記を記述。
POST送信時にURLパラメータ(idやpassword)もValidateしたい。POSTではnameというパラメータを送るつもり。

api.php
Route::post('store/{id}/{password}', 'UserController@store');
// Route::get('users/{id}/{password}', 'UserController@index');

サンプルとしてはpostのみ記載するが、getの際も問題なく動作しました。

Controller

nameを返すだけの記述。利用するFormRequestを指定。

UserController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\IndexRequest;
use App\Http\Requests\StoreRequest;

class UserController extends Controller
{
    function store(StoreRequest $request,$id,$password)
    {
        return $request->name;
    }

    // function index(IndexRequest $request,$id,$password){
    //     return $id;
    // }
}

FormRequest

下記のコマンドで生成。

php artisan make:request StoreRequest

そして実装。要点としては、

  • rulesとかmessagesとかは普通に記述
  • validationData()でパラメータを追加(id,password)
  • failedValidation()でバリデーションエラー時にカスタムJSONを返すようにする

という感じ。
項目毎に分岐分各ならカスタムで実装してもいいのでは?とは思うけど、ルールが統一できるのと、記述量もやや少なくても済むのかなと。

StoreRequest
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

class StoreRequest extends FormRequest
{
    //とりあえず認証はtrueで
    public function authorize()
    {
        return true;
    }

    //ルールの設定
    public function rules()
    {
        return [
            'id' => 'integer',
            'password' => 'required|min:4',
            'name' => 'required'
        ];
    }

    //カスタムメッセージ
    public function messages(){
        return [
            'id.integer' => 'id must be integer.',
            'password.required' => 'password must be required.',
            'password.min' => 'password must be at least 4 chars。',
            'name.required' => 'name must be required',
        ];
    }

    //URLパラメータも処理できるように
    protected function validationData()
    {
        return array_merge($this->request->all(), [
            'id' => $this->id,
            'password' => $this->password,
        ]);
    }

    //エラー時HTMLページにリダイレクトされないようにオーバーライド
    protected function failedValidation(Validator $validator)
    {

        //個人的ニーズに合わせ、項目別にエラーを返す仕様

        //任意の値を追加
        $response['status'] = 'NG';
        $response['date'] = date('Y-m-d');

        //もしidにエラーがあれば
        if($validator->errors()->has('id')) {
            $response['message'] = $validator->errors()->first('id');
            throw new HttpResponseException(response()->json($response, 422));
        }

        //もしpasswordにエラーがあれば
        if($validator->errors()->has('password')) {
            $response['message'] = $validator->errors()->first('password');
            throw new HttpResponseException(response()->json($response, 422));
        }

        //もしemailにエラーがあれば
        if($validator->errors()->has('name')) {
            $response['message'] = $validator->errors()->first('name');
            throw new HttpResponseException(response()->json($response, 422));
        }

        //全体のエラーを表示
        // $response['message'] = $validator->errors()->toArray();
        // throw new HttpResponseException(
        //     response()->json($response, 422)
        // );
    }
}

ちなみにget(index)の場合はnameパラメータ関連の処理を除去するだけ。

検証

以下で期待通りの動きをするか検証をする。

  1. http://localhost:8000/1/hogehoge + name = 'foo'でpostリクエスト(正常)
  2. http://localhost:8000/1/ho + name = 'foo'でポストリクエスト(passwordが4文字以下)
  3. http://localhost:8000/a/hogehoge + name = 'foo'でポストリクエスト(idが数字じゃない)
  4. http://localhost:8000/1/hogehoge + (nameなし)でpostリクエスト(nameなし)

以下、2の場合の結果。

{
    "status": "NG",
    "date": "2018-10-24",
    "message": "password must be at least 4 chars。"
}
14
18
0

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
14
18