Irindul
Irindul

Reputation: 406

Laravel validate array of object JSON

I have a POST endpoint on my Laravel 5.5 API, I used postman to test my route and here is the problem. I want to send an array of the same kind of object, like this:

[
  { 
   "name":"test",
   "tag":"TEST"
  },
  {
   "name":"test2",
   "tag":"TEST_2"
  }
]

But I can't manage to validate it properly.

in my controller, I have this:

$validator = Validator::make($requests->all(), [
 
   'name' => 'required|string',
   'tag' => 'required|string'
]);

if($validator->fails()) 
   //Warn user for errors 

I also tried with the simple

$this->validate($requests->all() .... )

I tried renaming the rules with '.name' and '*.name' but no success.

I tried replacing $request->all() with $request->input()but no success.

I also tried to loop over it but I get exceptions

foreach($request as $req){

  $validator = Validator::make($req ....) 

  //rest of the code
}

On the other hand, I can retrieve the data like this $datas = $request->all() and store them but there is no validation.

The only solution that seems to be working is naming my array:

{
 "data" : [
      { 
       "name":"test",
       "tag":"TEST"
      },
      {
       "name":"test2",
       "tag":"TEST_2"
      }
    ]
}

And then name the rules with 'data.*.name' but this obliges the API user to parse the array. Let suppose I have an array $array which I want to store, I need to do

$arrayParsed = ['data' => $array]

and call the API with $arrayParsed, which I think is a little redundant.

Is there a better way to handle the problem?

Upvotes: 12

Views: 21741

Answers (3)

K-Alex
K-Alex

Reputation: 380

I was able to do this in laravel 6 like the following via App\Http\Requests CustomRequestClass

public function rules()
{
    return [
        '*.name' => 'required',
        '*.tag' => 'required'
    ];
}

Upvotes: 7

Michael Aaron Wilson
Michael Aaron Wilson

Reputation: 1030

The approved answer works if your posting an array, however to take it a step further, I am needing to save multiple arrays. While that approach would work if I make two separate endpoints, what if I want to save everything inside one DB::transaction?

Viola:

POST:

{
"array1": [
    { "key1": "string", "key2": 1 },
    { "key1": "string", key2": 0 }
  ],
"array2": [
    { "key3": "string", "key4": 1 },
    { "key3": "string", "key4": 0 }
  ]
}

SERVER:

$this->validate($request, [
    'array1' => 'present|array',
    'array2' => 'present|array',
    'array1.*.key1' => 'required|string',
    'array1.*.key2' => 'required|integer',
    'array2.*.key3' => 'required|string',
    'array2.*.key4' => 'required|integer'
]);

DB::transaction(function() use($request) {
    foreach($request['array1'] as $x){
        ...do stuff here
    };
});

Note: 'present|array' accepts empty arrays whereas 'required|array' would reject them.

Upvotes: 3

Niraj Shah
Niraj Shah

Reputation: 15457

You can try to circumvent the issue by first doing:

$data = [ 'data' => $requests->all() ];

Then you can use the rule you suggested:

$validator = Validator::make($data, [
   'data.*.name' => 'required|string',
   'data.*.' => 'required|string'
]);

Not the most elegant solution but it solves your issue...

Upvotes: 25

Related Questions