Laravel Data

Spatie’s Laravel Data is a great package that allows you to define typed data objects in your application and use them for different purposes: as form requests, as resources, etc.
Scramble has Laravel Data support as a part of Scramble PRO package. You can get Scramble PRO here: https://scramble.dedoc.co/pro. After purchasing, you will receive the license key to your email.
Installation
Before installing Scramble PRO, make sure to update dedoc/scramble
to at least 0.12.9
.
Add the private repository to the list of your repositories in composer.json
"repositories": [ { "type": "composer", "url": "https://satis.dedoc.co" }],
Now, add the package to the list of your dependencies:
"require": { "dedoc/scramble-pro": "^0.7.3", "dedoc/scramble": "^0.12.9",}
And run composer update
.
When running composer update, you will be prompted to provide your credentials for the repository website. These credentials will authenticate your Composer session as having permission to download the Scramble PRO source code. To avoid manually typing these credentials, you may create a Composer auth.json file and use your license key in place of the password:
{ "http-basic": { "satis.dedoc.co": { "username": "youremail@company.com", "password": "YOUR-KEY-000000" } }}
You may quickly create an auth.json file via your terminal using the following command.
composer config http-basic.satis.dedoc.co \ youremail@company.com \ YOUR-KEY-000000
You should not commit your application’s auth.json
file into source control!
Usage
If you already configured routes for Scramble, after you install Scramble PRO – you’re done! Scramble will generate the schemas of Laravel Data objects used as form requests, or as API resources.
Documenting collection properties
Any Data object’s property can be marked as a collection of some other data object type and Scramble will document that.
You can use @property
PHPDoc annotation on the class.
use Illuminate\Support\Collection;use Illuminate\Support\Optional;use Spatie\LaravelData\Data;
/** * @property Optional|Collection<BookData> $books */class AuthorData extends Data{ public function __construct( public string $name, public Collection $books, ) { }}
If you want to mark collection property as Optional
or Lazy
, make sure you put these types first, before the collection type. Otherwise, Laravel Data won’t recognize the type correctly, and Scramble won’t document it as you expect.
// ✅ works as expected/** * @property Optional|Collection<BookData> $books */
// ❌ does not work/** * @property Collection<BookData>|Optional $books */
When using constructor property promotion, you can add the type to @param
annotation (but not the @var
annotation) of the constructor, so types are resolved properly. The description should be added right above the parameter.
use Illuminate\Support\Collection;use Illuminate\Support\Optional;use Spatie\LaravelData\Data;
class AuthorData extends Data{ /** * @param Optional|Collection<BookData> $books */ public function __construct( public string $title, /** List of books of this author */ public Collection $books, ) { }}
You can also use DataCollectionOf
attribute:
use Illuminate\Support\Collection;use Spatie\LaravelData\Attributes\DataCollectionOf;use Spatie\LaravelData\Lazy;use Spatie\LaravelData\Data;
class AuthorData extends Data{ public function __construct( public string $title, #[DataCollectionOf(BookData::class)] public Lazy|Collection $books, ) { }}
Requests
You can use Laravel Data objects as form requests. Scramble will automatically use the provided data object as a schema for the request body.
use App\Data\TodoData;
class TodoController extends Controller{ public function store(TodoData $todoData) { return /* ... */; }}
use Spatie\LaravelData\Data;use Spatie\LaravelData\Attributes\Validation\Min;use Spatie\LaravelData\Attributes\Validation\Max;
class TodoData extends Data{ public function __construct( #[Min(3), Max(255)] public string $title, public string $content, public bool $completed, ) {}}
Responses
When Laravel Data objects are returned from controller’s method, Scramble will generate a schema for the Data object as well.
use App\Data\TodoData;use App\Models\Todo;
class TodoController extends Controller{ public function show(Todo $todo) { return TodoData::from($todo); }}
use Spatie\LaravelData\Data;use Spatie\LaravelData\Attributes\Validation\Min;use Spatie\LaravelData\Attributes\Validation\Max;
class TodoData extends Data{ public function __construct( #[Min(3), Max(255)] public string $title, public string $content, public bool $completed, ) {}}
Data collection
Laravel Data allows to return collections of data objects from controllers’ methods. There are various ways of creating it and for now not all of them are properly supported by Scramble (but this is work in progress).
Here the list of the ways of creating data collections.
// ✅ supported (array of arrays)TodoData::collect([ ['title' => 'Sample title'],]);
// ✅ supported (collection)TodoData::collect(Todo::all());
// ✅ supported (explicitly providing the data collection type as a second argument)TodoData::collect(Todo::all(), DataCollection::class);TodoData::collect(Todo::paginate(), PaginatedDataCollection::class);TodoData::collect(Todo::cursorPaginate(), CursorPaginatedDataCollection::class);
// ❌ not supported// Scramble will not correctly document these responses (for now)// so you need to explicitly provide a data collection type// as a second argument.TodoData::collect(Todo::paginate());TodoData::collect(Todo::cursorPaginate());
So by returning a collection of data objects from a controller you’ll get a properly documented response.
use App\Data\TodoData;use App\Models\Todo;use Spatie\LaravelData\PaginatedDataCollection;
class TodoController extends Controller{ public function show(Todo $todo) { return TodoData::collect(Todo::paginate(), PaginatedDataCollection::class); }}
use Spatie\LaravelData\Data;use Spatie\LaravelData\Attributes\Validation\Min;use Spatie\LaravelData\Attributes\Validation\Max;
class TodoData extends Data{ public function __construct( #[Min(3), Max(255)] public string $title, public string $content, public bool $completed, ) {}}
Including and excluding properties
include
When using Lazy
properties, you can force including some properties by using include
method.
defaultIncluded
Lazy
properties can be included by default, by marking them as defaultIncluded
.
exclude
When using Lazy
properties, you can force excluding some properties by using exclude
method.
When using include
, defaultIncluded
, or exclude
, Scramble will not reference Laravel Data object as a schema component.
Context-aware schemas
Laravel Data objects can be used in a different contexts: as form requests (for data input) or as resources (for data output). This results in a different schema in some cases. For example, if you have a property with a default value public bool $completed = false
, this makes completed
property optional when data object is used as a form request, but it will ALWAYS be present in the response (hence required) when data object is used as a resource.
In such cases when schema for a data object is different in input and output contexts, Scramble will add Request
suffix for data object schema name when used as a form request. So in the prior example TodoData
data object became TodoDataRequest
.
use App\Data\TodoData;
class TodoController extends Controller{ public function store(TodoData $todoData) { return /* ... */; }
public function show(Todo $todo) { return TodoData::from($todo); }}
use Spatie\LaravelData\Data;use Spatie\LaravelData\Attributes\Validation\Min;use Spatie\LaravelData\Attributes\Validation\Max;
class TodoData extends Data{ public function __construct( #[Min(3), Max(255)] public string $title, public string $content = '', public bool $completed = false, ) {}}
Manually describing attributes
When needed, you can also add manual annotation to your data object properties, and it will be documented. You can add description, redefine property type, add examples, or provide default values.
Manual annotation is prioritized over type inference, so you can override types as you see fit.
use Spatie\LaravelData\Data;
class TodoData extends Data{ public function __construct( /** * The title of the todo item. * @example Make a good-looking docs page. */ public string $title,
/** * Details about todo item, the amount of things to be done. */ public string $content = '',
/** * Whether todo item is completed. * @var int * @default 0 */ public $completed = false, ) {}}
use App\Data\TodoData;use App\Models\Todo;
class TodoController extends Controller{ public function show(Todo $todo) { return TodoData::from($todo); }}
Supported features
Besides the described supported features, these features are also supported.
Attributes names mapping
By using PHP attributes MapName
or MapInputName
you can define rules for Laravel Data of how to map attribute names. For example, an attribute todoItem
can be represented as todo_item
in response (or request).
Wrapping
Laravel Data objects can be wrapped in some key, or wrapping can be skipped for some cases. Either way Scramble got this.
Accurate schema representation when Data object is used for Input or Output
When using data wrapping or attribute names mapping, the Data object used in different context (as a form request or as a resource) will have different schemas. Scramble PRO supports this case and will generate correct schemas.
Optional
/Lazy
support
Using these classes as property types will mark properties as optional for schemas.
include
/defaultIncluded
/exclude
support
Lazy
properties presence or absence can be enforced by using include
, exclude
methods. Specific lazy properties can be included by default by marking them included by default using defaultIncluded
method.
Is there something missing? The amount of features packed in Laravel Data is huge! Not every possible method is covered by Scramble PRO. When you become Scrambe PRO customer, you can request adding missing features and they will be added.