Resources
Resources define how Eloquent models are serialized into JSON:API response objects. Each resource maps a model to its type, id, attributes, relationships, links, and meta.
Creating a Resource
Use the artisan command:
php artisan api-toolkit:make-resource ProductResource --model=Product
# For resources without an Eloquent model (e.g. timestamps, stats):
php artisan api-toolkit:make-resource TimestampResource --plain
Or create one manually:
use BlueBeetle\ApiToolkit\Resources\Resource;
class ProductResource extends Resource
{
public function attributes($model): array
{
return [
'name' => $model->name,
'description' => $model->description,
'price' => $model->price,
'created_at' => $model->created_at->toIso8601String(),
];
}
}
Type and ID Resolution
By default, the toolkit resolves:
- ID — Uses the model's
public_idattribute if it exists, otherwise falls back to the primary key - Type — Uses the resource's
$typeproperty if set, then the model's table name, then derives it from the class name
You can customize this globally:
Resource::resolveIdUsing(fn ($model) => $model->uuid);
Resource::resolveTypeUsing(fn ($model, $resource) => Str::kebab(class_basename($model)));
Or set it per resource:
class ProductResource extends Resource
{
protected string $type = 'products';
// ...
}
Relationships
Define relationships by mapping names to resource classes:
class OrderResource extends Resource
{
public function attributes($model): array
{
return [
'total' => $model->total,
'status' => $model->status,
];
}
public function relationships(): array
{
return [
'customer' => CustomerResource::class,
'items' => OrderItemResource::class,
];
}
}
When a client requests ?include=customer,items, the related models are eager-loaded and included in the included array of the response. Relationship data always appears under relationships with a type/id reference.
Links and Meta
class ProductResource extends Resource
{
public function self($model): ?string
{
return route('api.products.show', $model);
}
public function links($model): array
{
return [
'purchase' => route('api.products.purchase', $model),
];
}
public function meta($model): array
{
return [
'stock_level' => $model->stock_count > 0 ? 'in_stock' : 'out_of_stock',
];
}
}
The self() link is automatically merged with any additional links from links(). If self() returns null, no self key appears in the output.
OpenAPI Schema
Define attribute types for automatic OpenAPI spec generation. The schema() method controls how your resource's attributes appear in the generated OpenAPI document.
Using String Shorthands
class ProductResource extends Resource
{
public function schema(): array
{
return [
'name' => 'string',
'quantity' => 'integer',
'price' => 'number',
'is_active' => 'boolean',
'tags' => 'array',
'settings' => 'object',
'birthday' => 'date',
'created_at' => 'datetime',
];
}
}
Available shorthands:
| Shorthand | OpenAPI Type |
|---|---|
string | { "type": "string" } |
integer / int | { "type": "integer" } |
number / float / double | { "type": "number" } |
boolean / bool | { "type": "boolean" } |
array | { "type": "array", "items": { "type": "string" } } |
object | { "type": "object" } |
date | { "type": "string", "format": "date" } |
datetime | { "type": "string", "format": "date-time" } |
Using Full OpenAPI Definitions
For more control, pass OpenAPI property objects directly. You can mix shorthands and full definitions:
public function schema(): array
{
return [
'name' => 'string',
'description' => ['type' => 'string', 'nullable' => true],
'status' => ['type' => 'string', 'enum' => ['active', 'inactive', 'draft']],
'price' => ['type' => 'number', 'format' => 'float', 'minimum' => 0],
'metadata' => ['type' => 'object', 'additionalProperties' => true],
];
}
Automatic Inference
If you don't define schema(), the toolkit infers types from your Eloquent model's casts:
| Cast | OpenAPI Type |
|---|---|
integer / int | integer |
float / double / decimal / decimal:N | number |
boolean / bool | boolean |
string | string |
array / json / collection | object |
date | string (format: date) |
datetime / immutable_datetime | string (format: date-time) |
timestamp | integer |
encrypted | string |
| Backed enum class | string or integer with enum values |
Internal columns (id, password, remember_token) are automatically excluded from the generated schema.