How to return JSON from Laravel Form Request validation errors

James Mills > Code & Development > How to return JSON from Laravel Form Request validation errors

UPDATE 10th June 2019 : I posted this article on LaravelUK Slack channel and David T gave me some valuable feedback.

You can force Laravel to always return only JSON by specifying the Accept header However, there may be instances where you want to force it regardless and the below article demonstrates how to do that.


Recently I have been using Laravel Form Request Validation instead of using inline validation. I find it much nicer to break things out into their own classes as much as possible so I was pleased when this made its way into the core framework.

If you are like me and you cannot get out of the habit of writing inline validation then don’t worry because the wonderful Jason McCreary has added an awesome feature to the Laravel Code Fixer Shift to convert inline controller validation to Form Requests.

When using Form Requests with API’s you will notice that if you hit an API route where the validation fails it will throw you to a 404 view.

My solution is to make my own FormRequest class which I put in the root API namespace namespace App\Http\Requests\Api;

<?php
namespace App\Http\Requests\Api;
use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Foundation\Http\FormRequest as LaravelFormRequest;
abstract class FormRequest extends LaravelFormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
abstract public function rules();
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
abstract public function authorize();
/**
* Handle a failed validation attempt.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator)
{
$errors = (new ValidationException($validator))->errors();
throw new HttpResponseException(
response()->json(['errors' => $errors], JsonResponse::HTTP_UNPROCESSABLE_ENTITY)
);
}
}
view raw FormRequest.php hosted with ❤ by GitHub

So your SearchController which uses the SearchRequest instead of the default Requeststays the same.

We just update the SearchRequest to use our custom FormRequest and not the default and we will get a nice JSON response when we have validation errors.

<?php

namespace App\Http\Requests\Api\Flight;

use Illuminate\Foundation\Http\FormRequest;

class SearchRequest extends FormRequest
{
    ...
}

So now our class will extend our own custom class

<?php

namespace App\Http\Requests\Api\Flight;

use App\Http\Requests\Api\FormRequest;

class SearchRequest extends FormRequest
{
    ...
}

So now when we hit the API endpoint we will get this

27 thoughts on “How to return JSON from Laravel Form Request validation errors

  1. Hi, I use another method in which we no need to create seprate request and extend it in form-request.

    just add below method “failedValidation” in form-request and it will transform data in JSON.

    “`
    use Illuminate\Http\Exceptions\HttpResponseException;
    class LoginRequest extends FormRequest
    {
    public function rules(): array
    {
    return [
    ’email’ => [‘required’, ‘string’, ’email’],
    ‘password’ => [‘required’, ‘string’],
    ];
    }

    /**
    * Get the error messages for the defined validation rules.*
    * @param Validator $validator
    * @return array
    */
    protected function failedValidation(Validator $validator): array
    {
    throw new HttpResponseException(response()->json([
    ‘success’ => false,
    ‘errors’ => $validator->errors(),
    ], 422));
    }
    }
    “`

  2. Look at there, make an a Header Accept: application/json for implement a default logic to get a json response wich every api request

  3. hi , i get errors like ReflectionException: Class App\Http\Requests\User\updateProfileRequest does not exist in file ../vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php on line 25

    when i tried to call updateProfileRequest on my controller

    i already try step by step like above.
    btw, thanks for sharing it helps man 🙂

    1. Hi Dedi, is this related to returning data from an API endpoint? Can you link me to a StackOverflow post where you explain your issues with a little more details and I will try to help.

    2. Hey there,

      I ran into the same issue, on your extended FormRequest class make sure you’ve imported all the required classes 🙂 i.e. Validator requires you to use Illuminate\Contracts\Validation\Validator; etc

  4. This exception seems pointless:

    “`
    $errors = (new ValidationException($validator))->errors();
    “`

    Might as well use $validator->errors() directly instead. Also, using Illuminate\Http\JsonResponse instead of Illuminate\Http\Response for the response code seems a little wonky.

    Cheers

    1. Thanks for your feedback M. The solution I came up with works for my needs and I thought I would share to help out others. Given this articles organic search volume it would suggest others are also struggling with this. I’ll certainly have a look at your suggestions and see if I should update the article.

  5. I can’t seem to get this to work, still being redirected if validation fails rather than seeing a JSON response.

    The `failedValidation` method in my new FormRequest class doesn’t appear to be firing at all. The class is being loaded, I checked by adding a constructor with a `dd` inside of it.

    1. Richard, did you ever get this sorted? Have you tried running dump autoload? If the constructor is getting called that only means that the class is being constructed not that the function is being called when we would expect it to. Happy to jump in a screen share with you if that would help?

  6. This is exactly what I’m looking for. I tried it out but I’m getting the following error:
    “`
    Declaration of App\Http\Requests\BaseFormRequest::failedValidation(Illuminate\Validation\Validator $validator) should be compatible with Illuminate\Foundation\Http\FormRequest::failedValidation(Illuminate\Contracts\Validation\Validator $validator)
    “`
    Apparently I gotta return the same type of data the parent method is returning. Any way around this?
    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *