Scramble 0.11.0 is here! Laravel Data support, schema enforcement and more
Learn more

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

Installation instructions for `dedoc/scramble-pro`

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 to the @var annotation) of the constructor, so types are resolved properly. The description should be added right above the parameter (where @var goes).

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 /* ... */;
    }
}
Resulting documentation
todo.store
post
https://todos.app/api/todo
Request
application/json
Body
TodoData
title
string
required
>= 3 characters
<= 255 characters
content
string
required
completed
boolean
required

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);
    }
}
Resulting documentation
todo.show
get
https://todos.app/api/todo/{todo}
Responses
200
·
OK
Body
TodoData
title
string
required
>= 3 characters
<= 255 characters
content
string
required
completed
boolean
required

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);
    }
}
Resulting documentation
todo.show
get
https://todos.app/api/todo/{todo}
Responses
200
·
OK
The paginated collection of `TodoData`
Body
object
data
TodoData[]
required
The list of items
title
string
required
>= 3 characters
<= 255 characters
content
string
required
completed
boolean
required
links
object[]
required
Generated paginator links.
url
string or null
required
label
string
required
active
boolean
required
meta
object
required
current_page
integer
required
first_page_url
string
required
from
integer or null
required
last_page
integer
required
last_page_url
string
required
next_page_url
string or null
required
path
string or null
required
Base path for paginator generated URLs.
per_page
integer
required
Number of items shown per page.
prev_page_url
string or null
required
to
integer or null
required
Number of the last item in the slice.
total
integer
required
Total number of items being paginated.

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);
    }
}
Resulting documentation
todo.store
post
https://todos.app/api/todo
Request
application/json
Body
TodoDataRequest
title
string
required
>= 3 characters
<= 255 characters
content
string
Default
''
completed
boolean
Default
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,
    ) {}
}
Resulting documentation
todo.show
get
https://todos.app/api/todo/{todo}
Responses
200
·
OK
Body
TodoData
title
string
required
The title of the todo item
Example
Make a good-looking docs page.
content
string
required
Details about todo item, the amount of things to be done
Default
''
completed
integer
required
Whether todo item is completed
Default
0

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.

Scramble PRO
Comprehensive API documentation generation for Spatie’s Laravel Data.