Unified Data Management in Laravel with Laravel-Data
Overview of the Data Definition Problem
Modern web applications often suffer from a "multiple definition" problem. When building a feature, you typically define the same set of attributes in a middle_name field to your database but forget to update the API resource, your frontend breaks.
Prerequisites and Toolkit
To follow this guide, you should be comfortable with
Key Libraries & Tools
- Laravel-Data: The core package that creates powerful data objects to replace form requests and API resources.
- TypeScriptTransformer: A built-in feature of the package that scans yourPHPclasses and generates matchingTypeScriptdefinitions.
- Inertia.js: Frequently used alongside this package to bridge the gap between backend data and frontendReactorVuecomponents.
Code Walkthrough: Implementing a Data Object
Let's replace the standard StoreContactRequest and a ContactResource, we create a ContactData class.
namespace App\Data;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Attributes\Validation\Email;
class ContactData extends Data
{
public function __construct(
public string $name,
#[Email]
public string $email,
public ?string $address,
) {}
}
By extending the Data class, this object now performs multiple roles. When used in a controller, it automatically validates incoming request data based on the property types. For example, the string $name property implies a required|string validation rule. If you want more specific constraints, use attributes like #[Email].
In your controller, you can swap out the standard request and resource calls:
public function update(ContactData $contactData, Contact $contact)
{
$contact->update($contactData->toArray());
return back();
}
public function show(Contact $contact)
{
return ContactData::from($contact);
}
The from() method is a "smart" factory. It accepts a model, an array, or a request and maps the attributes automatically. This eliminates the manual mapping usually found in
Automated TypeScript Integration
One of the most powerful features of
php artisan typescript:transform
This generates interfaces that match your ?string), it becomes optional or nullable in
Advanced Features: Nesting and Route Actions
Real-world data is rarely flat. Project has many Guests, you can define a ProjectData class that contains a collection of GuestData objects. The
In the upcoming Version 4, the package introduces a Route Action Helper. This tool scans your
Tips & Gotchas
While
Best Practice: Always use the from() method rather than manual instantiation. It handles the heavy lifting of converting models and multi-dimensional arrays into the correct object format. If you need to hide sensitive data like addresses for certain users, use the except() or only() methods on the data object to filter the output dynamically.
