DEV Community

A0mineTV
A0mineTV

Posted on

Laravel Resources and Collections: A Complete Guide to API Response Transformation

Laravel's API Resources provide a powerful and elegant way to transform your Eloquent models and model collections into JSON responses. Whether you're building a REST API or need structured data output, resources give you complete control over how your data is presented to consumers.

In this comprehensive guide, we'll explore both individual Resources and Resource Collections, including automatic pagination handling in Laravel 12.

What are Laravel Resources ?

Laravel Resources act as a transformation layer between your Eloquent models and the JSON responses that are returned to users of your application. They allow you to expressively and easily transform models and model collections into JSON.

Basic Resource Implementation

Let's start with a simple ArticleResource that transforms an Article model:

The Model

First, here's our basic Article model:

<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'body', 'published_at'];

    protected $casts = ['published_at' => 'datetime'];
}
Enter fullscreen mode Exit fullscreen mode

The Resource

<?php

declare(strict_types=1);

namespace App\Http\Resources;

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

final class ArticleResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'published_at' => optional($this->published_at)?->toIso8601String(),
            'created_at' => $this->created_at->toIso8601String(),
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the Resource

In your controller, you can use the resource like this:

<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Resources\ArticleResource;
use App\Models\Article;

final class ArticleController extends Controller
{
    public function show(Article $article): ArticleResource
    {
        return new ArticleResource($article);
    }
}
Enter fullscreen mode Exit fullscreen mode

This will return a JSON response like:

{
  "data": {
    "id": 1,
    "title": "Understanding Laravel Resources",
    "body": "Laravel Resources provide a powerful way...",
    "published_at": "2024-01-15T10:30:00Z",
    "created_at": "2024-01-15T08:00:00Z"
  }
}
Enter fullscreen mode Exit fullscreen mode

Resource Collections with Automatic Pagination

When dealing with multiple models, Laravel provides Resource Collections. Here's where Laravel 12's auto-mapping feature really shines:

The Collection Resource

<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use JsonSerializable;

final class ArticleCollection extends JsonResource
{
    /** Map each item with ArticleResource automatically */
    public string $collects = ArticleResource::class;

    /** Preserve default structure (data + links + meta if paginator) */
    public function toArray(Request $request): array|JsonSerializable|Arrayable
    {
        return parent::toArray($request);
    }

    public function with($request): array
    {
        return [
            'meta_extra' => ['generate_at' => now()->toIso8601String()]
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the Collection with Pagination

<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Resources\ArticleCollection;
use App\Models\Article;

final class ArticleController extends Controller
{
    public function index(): ArticleCollection
    {
        return new ArticleCollection(
            Article::query()->latest()->paginate(10)
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Setting up Routes

<?php

use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;

Route::get('/articles', [ArticleController::class, 'index'])->name('articles.index');
Route::get('/articles/{article}', [ArticleController::class, 'show'])->name('articles.show');
Enter fullscreen mode Exit fullscreen mode

The Magic: Laravel 12's Auto-Collection Feature

The key innovation in the ArticleCollection is the $collects property:

public string $collects = ArticleResource::class;
Enter fullscreen mode Exit fullscreen mode

This tells Laravel to automatically wrap each item in the collection with the specified resource class. When you pass a paginated collection to this resource, Laravel will:

  1. Automatically map each article through ArticleResource
  2. Preserve pagination metadata (current page, total, links, etc.)
  3. Maintain the default Laravel structure with data, links, and meta keys

Response Structure

Single Resource Response

{
  "data": {
    "id": 1,
    "title": "Understanding Laravel Resources",
    "body": "Laravel Resources provide a powerful way...",
    "published_at": "2024-01-15T10:30:00Z",
    "created_at": "2024-01-15T08:00:00Z"
  }
}
Enter fullscreen mode Exit fullscreen mode

Paginated Collection Response

{
  "data": [
    {
      "id": 1,
      "title": "Understanding Laravel Resources",
      "body": "Laravel Resources provide a powerful way...",
      "published_at": "2024-01-15T10:30:00Z",
      "created_at": "2024-01-15T08:00:00Z"
    },
    {
      "id": 2,
      "title": "Another Article",
      "body": "Content of another article...",
      "published_at": "2024-01-16T14:20:00Z",
      "created_at": "2024-01-16T12:00:00Z"
    }
  ],
  "links": {
    "first": "http://example.com/articles?page=1",
    "last": "http://example.com/articles?page=5",
    "prev": null,
    "next": "http://example.com/articles?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 5,
    "path": "http://example.com/articles",
    "per_page": 10,
    "to": 10,
    "total": 50
  },
  "meta_extra": {
    "generate_at": "2024-01-15T15:45:30Z"
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Benefits

1. Automatic Item Transformation

The $collects property eliminates the need to manually loop through items and apply transformations.

2. Preserved Pagination

Laravel automatically maintains all pagination metadata, including links and meta information.

3. Consistent Structure

Your API responses maintain a consistent structure whether returning single items or collections.

4. Extensible

You can easily add extra metadata using the with() method without disrupting the core structure.

5. Type Safety

With proper typing, you get better IDE support and early error detection.

Best Practices

  1. Use final classes for resources when you don't plan to extend them
  2. Declare strict types for better type safety
  3. Handle optional relationships gracefully with optional()
  4. Use ISO 8601 format for dates in APIs
  5. Keep transformations simple - complex logic should be in the model or service layer

Conclusion

Laravel Resources and Collections provide an elegant solution for API response transformation. The auto-collection feature in Laravel 12 makes working with paginated data seamless while maintaining flexibility for customization.

By leveraging the $collects property and proper resource structure, you can build robust, consistent APIs with minimal code while taking advantage of Laravel's powerful pagination features.

Whether you're building a simple REST API or a complex data transformation layer, Laravel Resources offer the perfect balance of simplicity and power for your application's needs.

Top comments (0)