Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
18
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@zaburo

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

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。"
}
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
18
Help us understand the problem. What are the problem?