Eloquent Serialization — Model JSON Transformation in Laravel
In this tutorial, you will learn about Eloquent Serialization. We cover key concepts, practical examples, and best practices to help you master this topic.
Laravel Eloquent serialization controls how models and collections convert to arrays and JSON, with API Resources providing fine-grained transformation control for API responses.
What You'll Learn
By the end of this tutorial, you'll customize model serialization with $hidden and $appends, use API Resources for JSON transformation, handle pagination, and conditionally include attributes.
Why Serialization Matters
Every API response requires careful control over which model attributes are exposed. Proper serialization prevents data leaks and provides consistent API output.
Real-World Use
A Laravel API uses UserResource to expose public profile data while hiding emails from non-admin users. The resource conditionally includes posts count and recent activity.
Serialization Path
flowchart LR
A[Eloquent ORM] --> B[Serialization]
B --> C[Cast & Append]
B --> D[API Resources]
B --> E[Conditional Load]
B --> F[Pagination]
B --> G{You Are Here}
style G fill:#f90,color:#fff
Basic Serialization Control
Hide sensitive attributes and append accessor values.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
protected $hidden = [
"password",
"remember_token",
"two_factor_secret",
];
protected $appends = [
"full_name",
"is_admin",
];
protected function fullName(): Attribute {
return Attribute::make(get: fn() => "$this->first_name $this->last_name");
}
protected function isAdmin(): Attribute {
return Attribute::make(get: fn() => $this->role === "admin");
}
}
Conditional Attribute Inclusion
Dynamically include attributes in serialization.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Post extends Model {
protected function excerpt(): Attribute {
return Attribute::make(
get: fn(mixed $value) => $value ?? Str::limit($this->content, 200),
);
}
// Make visible/invisible at runtime
}
// Usage
$post->makeVisible("author_email");
$post->makeHidden("internal_notes");
API Resources
Full control over JSON API output.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource {
public function toArray(Request $request): array {
return [
"id" => $this->id,
"title" => $this->title,
"slug" => $this->slug,
"excerpt" => $this->excerpt,
"published_at" => $this->published_at?->diffForHumans(),
"author" => new UserResource($this->whenLoaded("author")),
"tags" => TagResource::collection($this->whenLoaded("tags")),
"comments_count" => $this->whenCounted("comments"),
"can" => [
"edit" => $request->user()?->can("update", $this->resource),
"delete" => $request->user()?->can("delete", $this->resource),
],
];
}
}
Resource Collections
Handle paginated and collection responses.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PostCollection extends ResourceCollection {
public $collects = PostResource::class;
public function toArray(Request $request): array {
return [
"data" => $this->collection,
"meta" => [
"total" => $this->total(),
"current_page" => $this->currentPage(),
"per_page" => $this->perPage(),
"last_page" => $this->lastPage(),
],
"links" => [
"first" => $this->url(1),
"last" => $this->url($this->lastPage()),
"prev" => $this->previousPageUrl(),
"next" => $this->nextPageUrl(),
],
];
}
}
Conditional Relationships
Include relationships only when loaded.
<?php
namespace App\Http\Resources;
class OrderResource extends JsonResource {
public function toArray(Request $request): array {
return [
"id" => $this->id,
"total" => $this->total,
"status" => $this->status,
"items" => OrderItemResource::collection($this->whenLoaded("items")),
"customer" => new CustomerResource($this->whenLoaded("customer")),
"payment" => new PaymentResource($this->whenLoaded("payment")),
];
}
}
// In controller
return new OrderResource(Order::with(["items", "customer"])->findOrFail($id));
Common Mistakes
1. Exposing Sensitive Data
Leaving password, tokens, or emails in $hidden accidentally. Always review serialized output.
2. N+1 in API Resources
Accessing $this->relation without whenLoaded causes N+1. Always use whenLoaded for relations.
3. Over-Appending Attributes
Every $appends attribute runs on every serialization. Keep appends minimal.
4. Inconsistent Resource Naming
Use ResourceCollection for collections, JsonResource for single models.
5. Not Using Pagination for Lists
Returning all records in list endpoints causes performance issues. Always paginate.
Practice Questions
1. How do you hide attributes from JSON output?
Add attributes to the $hidden array on the model.
2. What is whenLoaded used for?
Conditionally including relationships in resources only when they are loaded.
3. How do you append accessor values to JSON?
Add the accessor name to the $appends array.
4. What is the difference between JsonResource and ResourceCollection?
JsonResource transforms a single model. ResourceCollection transforms a collection.
5. Challenge: Create an API resource with conditional relationship inclusion.
<?php
class UserResource extends JsonResource {
public function toArray(Request $r): array {
return [
"id" => $this->id,
"name" => $this->name,
"email" => $this->when($r->user()?->isAdmin(), $this->email),
"posts" => PostResource::collection($this->whenLoaded("posts")),
"posts_count" => $this->whenCounted("posts"),
];
}
}
FAQ
Mini Project: User API Resource
Build a complete user API resource with conditional exposure.
<?php
class UserResource extends JsonResource {
public function toArray(Request $request): array {
return [
"id" => $this->hashId(),
"display_name" => $this->display_name,
"avatar" => $this->avatar_url,
"joined" => $this->created_at->diffForHumans(),
"email" => $this->when($this->email_visible, $this->email),
"is_following" => $this->when($request->user(), fn() => $request->user()->isFollowing($this->resource)),
];
}
}
What's Next
Eloquent Eager Loading Eloquent Performance Eloquent API Resources
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro