Skip to main content

Transformers Layer with league/fractal

In This Document

Introduction

In Laravel development, the Transformers layer plays a crucial role in shaping data for API responses. The league/fractal package is widely adopted for this purpose, offering a flexible and powerful toolset to transform raw data into a consistent and well-structured format suitable for API consumers.

What are Transformers?

Transformers are classes that convert your internal data structures into standardized API responses, ensuring consistency and proper formatting across your entire API.

Why Transformers?

Transformers help decouple the data retrieval process from the API response formatting. By employing Transformers, you can ensure that the data returned by your API is presented in a standardized way, promoting consistency and simplifying the maintenance of your codebase.

Installation of league/fractal

To get started with league/fractal, you need to install the package using Composer:

Terminal
composer require league/fractal

Once installed, you can create Transformers to define how your data should be represented in API responses.

Implementation Guide

Creating Transformers

Transformers are classes responsible for converting raw data into a specific structure for API responses. In Laravel, Transformers often extend the League\Fractal\TransformerAbstract class.

Basic Transformer

app/Transformers/UserTransformer.php
<?php

namespace App\Transformers;

use App\Models\User;
use League\Fractal\TransformerAbstract;

class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
return [
'id' => (int) $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at->toIso8601String(),
'updated_at' => $user->updated_at->toIso8601String(),
];
}
}

Transformer with Relationships

app/Transformers/PostTransformer.php
<?php

namespace App\Transformers;

use App\Models\Post;
use League\Fractal\TransformerAbstract;

class PostTransformer extends TransformerAbstract
{
protected $availableIncludes = [
'author', 'comments'
];

public function transform(Post $post)
{
return [
'id' => (int) $post->id,
'title' => $post->title,
'content' => $post->content,
'slug' => $post->slug,
'published' => (bool) $post->published,
'created_at' => $post->created_at->toIso8601String(),
'updated_at' => $post->updated_at->toIso8601String(),
];
}

public function includeAuthor(Post $post)
{
return $this->item($post->author, new UserTransformer());
}

public function includeComments(Post $post)
{
return $this->collection($post->comments, new CommentTransformer());
}
}

Advanced Features

Pagination

Fractal provides support for paginated results:

Paginated Response
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use App\Transformers\PostTransformer;
use Illuminate\Http\Request;

class PostController extends Controller
{
public function index(Request $request)
{
$paginator = Post::paginate(10);

$posts = $paginator->getCollection();

$response = fractal()
->collection($posts)
->transformWith(new PostTransformer())
->paginateWith(new \League\Fractal\Pagination\IlluminatePaginatorAdapter($paginator))
->toArray();

return response()->json($response);
}
}

Custom Serializers

Fractal allows you to customize the structure of your API responses using serializers:

Custom Serializer
<?php

namespace App\Serializers;

use League\Fractal\Serializer\ArraySerializer;

class CustomSerializer extends ArraySerializer
{
public function collection($resourceKey, array $data)
{
return $resourceKey ? [$resourceKey => $data] : $data;
}

public function item($resourceKey, array $data)
{
return $resourceKey ? [$resourceKey => $data] : $data;
}
}
Using Custom Serializer
return fractal()
->item($user)
->transformWith(new UserTransformer())
->serializeWith(new CustomSerializer())
->toArray();

Conditional Attributes

You can conditionally include attributes in your transformers:

Conditional Attributes
<?php

namespace App\Transformers;

use App\Models\User;
use League\Fractal\TransformerAbstract;

class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
$data = [
'id' => (int) $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at->toIso8601String(),
];

// Only include admin status for admin users
if ($user->isAdmin()) {
$data['is_admin'] = true;
}

// Only include private data if the authenticated user is viewing their own profile
if (auth()->id() === $user->id) {
$data['phone'] = $user->phone;
$data['address'] = $user->address;
}

return $data;
}
}

Best Practices

Maintain Consistency

  • Use the same format for all API responses
  • Keep date formats consistent (ISO 8601 is recommended)
  • Use consistent naming conventions (camelCase or snake_case)
  • Always cast IDs and boolean values to their proper types
Consistent Formatting
return [
'id' => (int) $model->id,
'is_active' => (bool) $model->is_active,
'created_at' => $model->created_at->toIso8601String(),
];

Conclusion

Implementing the Transformers layer using league/fractal in Laravel contributes to a cleaner and more maintainable codebase. By separating the concerns of data transformation from the rest of your application logic, you ensure that your API responses are consistent and easily adaptable to future changes.

Remember to explore the advanced features of league/fractal to handle more complex scenarios in your API development, such as includes, pagination, and custom serializers.