Laravel cookbook · Beginner

Shape JSON responses with API Resources

Returning models directly leaks columns and makes response formats drift.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Define an API Resource per model that lists exactly which fields are returned, includes relations only when they were eager loaded, and adds conditional fields for privileged users.

Solution

<?php
// app/Http/Resources/OrderResource.php
namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class OrderResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'status' => $this->status->value,
            'total' => $this->total_cents / 100,
            'placed_at' => $this->created_at->toIso8601String(),
            'customer' => new CustomerResource($this->whenLoaded('customer')),
            'lines' => OrderLineResource::collection($this->whenLoaded('lines')),
            'line_count' => $this->whenCounted('lines'),
            'internal_notes' => $this->when($request->user()?->isAdmin(), $this->internal_notes),
        ];
    }
}
<?php
// in a controller
use App\Http\Resources\OrderResource;
use App\Models\Order;

return OrderResource::collection(
    Order::with('customer')->withCount('lines')->latest()->paginate(25)
);

Pitfalls

  • Accessing relations in resources without eager loading, causing N+1 queries.
  • Returning $model->toArray() and relying on $hidden, which is easy to forget for new columns.
  • Changing field names in place; version the API or add new fields alongside old ones.

Variations

  • OrderResource::collection($paginator) includes pagination links and meta automatically.
  • Use #[UseResource(OrderResource::class)] on the model to call $order->toResource().

Further reading: Eloquent API Resources

Reference: https://laravel.com/docs/13.x/eloquent-resources

More Laravel recipes

Was this page helpful?