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

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

More than 1 year has passed since last update.

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。"
}
zaburo
こんにちは。自分用のメモをだらだら公開しています。
Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした