Skip to main content
You can add extra properties to your data objects when they are transformed into a resource:
SongData::from(Song::first())->additional([
    'year' => 1987,
]);
Output:
[
    'name' => 'Never gonna give you up',
    'artist' => 'Rick Astley',
    'year' => 1987,
]

Using Closures

When using a closure, you have access to the underlying data object:
SongData::from(Song::first())->additional([
    'slug' => fn(SongData $songData) => Str::slug($songData->title),
]);
Output:
[
    'name' => 'Never gonna give you up',
    'artist' => 'Rick Astley',
    'slug' => 'never-gonna-give-you-up',
]

The with Method

Add extra properties by overwriting the with method within your data object:
class SongData extends Data
{
    public function __construct(
        public int $id,
        public string $title,
        public string $artist
    ) {
    }

    public static function fromModel(Song $song): self
    {
        return new self(
            $song->id,
            $song->title,
            $song->artist
        );
    }
    
    public function with()
    {
        return [
            'endpoints' => [
                'show' => action([SongsController::class, 'show'], $this->id),
                'edit' => action([SongsController::class, 'edit'], $this->id),
                'delete' => action([SongsController::class, 'delete'], $this->id),
            ]
        ];
    }
}
Now each transformed data object contains an endpoints key:
[
    'id' => 1,
    'name' => 'Never gonna give you up',
    'artist' => 'Rick Astley',
    'endpoints' => [
        'show' => 'https://spatie.be/songs/1',
        'edit' => 'https://spatie.be/songs/1',
        'delete' => 'https://spatie.be/songs/1',
    ],
]

Use Cases

Appending properties is useful for:

API Endpoints

Add related API endpoints for the resource

Computed Values

Include calculated or derived properties

Metadata

Attach metadata like timestamps or versions

Permissions

Include user-specific permission flags
The with method is called every time the data object is transformed, making it perfect for dynamic properties that depend on the current state.

Build docs developers (and LLMs) love