Return Laravel Json Resource as Associative Array

I recently ran into the same issue as mentioned in this stackoverflow thread: https://stackoverflow.com/questions/52613298/return-array-in-laravel-api-resource-without-reordering-keys If you have custom data structures and you want to use JsonResource’s for constency sake, read further to make sure your data is intact when it is send to the client.

At a certain point in time, when building an API in Laravel, you may have a requirement to run a report on some data living in your app. The resulting data-structure of this report can take different forms due to its nature or some other reason. Maybe it’s more performant to use a specific data format so the client does not have to do the heavy lifting or vice-versa, etc…

For example: when generating a report to collect the total number of sales invoices per client and invoice type, you probably already know we’ll do a simple GROUP BY on client_id and invoice_type. The result will look something like this:


[
  "1" => [
    "invoice" => 3,
    "credit_note" => 1
  ],
  "2" => [
    "invoice" => 120,
    "credit_note" => 6
  ],
  // ... n clients
]

When you use the above result as an input for a JsonResource-object in Laravel, you’ll end up with something like this on the client:


data: [
  {
    "invoice": 3,
    "credit_note": 1
  },
  {
    "invoice": 120,
    "credit_note": 6
  },
  [
    {
      "invoice": 120,
      "credit_note": 9
    },
    {
      "invoice": 7,
      "credit_note": 45
    }
  ],
  // ... n clients
]

Not exactly what you’d want, right? The underlying issue here is that Laravel uses a filter-method when parsing the provided resource (Model, array, stdClass, …) which removes unnecessary fields and keys. In this case, well, not so unnecessary data. The solution is quite simple, as always! In the custom JsonResource-class you created, you just need to override the filter-method:


class MyCustomResource extends JsonResource
{
    /**
     * Keep resource keys as they are.
     * If set to `false` (default), the JsonResource's filter will flatten the array/collection without numerical keys
     *
     * @var boolean
     */
    protected $preserveKeys = true;
}