18

I'm trying to use Laravel validation to generate custom error message, however I'm unable to find the function I should be overriding.

Route: POST:/entries/ uses EntryController@store which uses EntryStoreRequest to perform validation.

EntryStoreRequest

namespace App\Api\V1\Requests;

class EntryStoreRequest extends ApiRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'message' => [
                'string',
                'required',
                'max:65535',
            ],
            'code' => [
                'string',
                'max:255',
                'nullable'
            ],
            'file' => [
                'string',
                'max:255',
                'nullable'
            ],
            'line' => [
                'string',
                'max:255',
                'nullable'
            ],
            'stack' => [
                'string',
                'max:65535',
                'nullable'
            ]
        ];
    }
}

ApiRequest

namespace App\Api\V1\Requests;

use Illuminate\Foundation\Http\FormRequest;

abstract class ApiRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }
}

The errors are currently returned as:

{
    "message": "The given data was invalid.",
    "errors": {
        "message": [
            "The message field is required."
        ]
    }
}

I want to format them as:

{
    "data": [],
    "meta: {
        "message": "The given data was invalid.",
        "errors": {
            "message": [
                "The message field is required."
            ]
        }
}

How can I achieve this within the ApiRequest class?

Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291
eithed
  • 3,933
  • 6
  • 40
  • 60

2 Answers2

43

If you want to customize validation response only for selected Request class, you need to add failedValidation() message to this class:

protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
    $response = new JsonResponse(['data' => [], 
             'meta' => [
                'message' => 'The given data is invalid', 
                'errors' => $validator->errors()
             ]], 422);

    throw new \Illuminate\Validation\ValidationException($validator, $response);
}

This way you don't need to change anything in Handler and have this custom response only for this single class.

And if you want to change format globally for all responses you should add to app\Exceptions\Handler.php file the following method:

protected function invalidJson($request, ValidationException $exception)
{
    return response()->json([
             'data' => [], 
             'meta' => [
                'message' => 'The given data is invalid', 
                'errors' => $exception->errors()
             ]
             ], $exception->status);
}

You can read about this also in Upgrade guide in Exception Format section

Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291
  • Won't that define such responses for all validations? What can I do to define above mentioned format only for given Request class? – eithed Oct 10 '17 at 15:29
  • Silly me - I've been looking at this method before, and even overrode it in `ApiRequest` class as `protected function failedValidation(Validator $validator)` to which I've gotten a `Class App\Api\V1\Requests\EntryStoreRequest does not exist` which doesn't really explain anything. Your answer provided me with an explanation to that as well :) Thanks! – eithed Oct 10 '17 at 16:12
  • Thanks for the answer. It works for me. Really helpful. Thanks @MarcinNabiałek – Saifur Rahman Jun 21 '18 at 08:21
0

For those who don't want to use JsonResponse, here was what I did for mine

protected function failedValidation(Validator $validator) {
        // if you want, log something here with $this->validationData(), $validator->errors()
        
        $response = redirect($this->getRedirectUrl())
            ->with('var1', 'my var 1') // custom flash variable to send if needed
            ->with('var2', 'my var 2')
            ->withErrors($validator)
            ->withInput();
        
        throw new ValidationException($validator, $response);
    }
4givN
  • 2,936
  • 2
  • 22
  • 51