Search code examples
phpjsonlaravel-routinglaravel-6

Laravel 6 API request validate array of objects before saving


Problem: How can I correctly validate an array of JSON objects sent via an API request?

Situation:

I sent a post request of an array of JSON objects to be saved. However, I cant make the validation work.

JSON

{
    "answers": [
        {
            "title": "hello World",
            "question_id": "1"
        },
        {
            "title": "hello World 2",
            "question_id": "2"
        }
    ]
}

Attempt #1

Route::post('answer/multiple', function (Request $request) {
    $answers = $request->answers;
    foreach ($answers as $answer) {
        $answer->validate([
            'title' => 'required',
            'question_id' => 'required',
        ]);
        $new_answer = new Answer();
        $new_answer->title = $answer['title'];
        $new_answer->question_id = $answer['question_id'];
        $new_answer->save();
    }
    return response()->json($request);
});

I also tried looping through each one to validate, sadly it does not work.

Attempt #2

Route::post('answer/multiple', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'answer.*.title' => 'required',
        'answer.*.question_id' => 'required',
    ]);
    $answers = $request->answers;
    foreach ($answers as $answer) {
        $new_answer = new Answer();
        $new_answer->title = $answer['title'];
        $new_answer->question_id = $answer['question_id'];
        $new_answer->save();
    }
    return response()->json($request);
});

In this one, the validation is ignored.


Solution

  • Unlike the $this->validate() controller method, the Validator::make() static function will not throw an error if validation fails.

    You will need to check if it has failed and return the error messages using the ->fails() Validator method:

    $validator = Validator::make($request->all(), [
        'answer.*.title' => 'required',
        'answer.*.question_id' => 'required',
    ]);
    
    if ($validator->fails()) { 
        return redirect('post/create')
            ->withErrors($validator)
            ->withInput();
    }
    
    foreach ($request->answers as $answer) {
        $new_answer = new Answer();
        $new_answer->title = $answer['title'];
        $new_answer->question_id = $answer['question_id'];
        $new_answer->save();
    }
    
    return response()->json($request);
    

    Alternatively, you can use the $this->validate() method:

    $validatedData = $this->validate($request, [
        'answer.*.title' => 'required',
        'answer.*.question_id' => 'required',
    ]);
    

    Note that we use $request instead of $request->all().

    Also note that when using this method, you will get an array of answers in $validatedData, so you will need to change your code accordingly.