First impressions on Laravel API Resources

Last night Taylor Otwell finally introduced what can be the beginning of replacing Fractal when developing APIs on Laravel 5.5. This is my first trial-and-run at it.

The interesting stuff starts at step 4.

1- Install clean Laravel 5.5 project

composer create-project laravel/laravel responses dev-develop
cd responses
touch database/database.sqlite
php artisan make:model Post -mfa
php artisan make:resource UsersWithPostsResource
php artisan make:resource PostsResource
php artisan make:controller UsersController --resource

Change your .env file to use SQLite and remove every other database variable.

DB_CONNECTION=sqlite

2- Prepping the database

  • The posts migration database/migrations/______create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('body');
$table->unsignedInteger('user_id');
$table->timestamps();
});
  • The Post Factory database/factories/PostFactory.php
<?php

use
Faker\Generator as Faker;

$factory->define(App\Post::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'body' => $faker->paragraph,
'user_id' => function () {
return factory(\App\User::class);
}
];
});
  • The User has Posts relationship app/User.php
public function posts()
{
return $this->hasMany(Post::class);
}
  • Avoid Mass Assignment on Posts app/Post.php
<?php

namespace
App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
protected $guarded = [];
}
  • Seeding the database
php artisan migrate:fresh
php artisan tinker
factory(App\Post::class)->times(2)->create();
factory(App\Post::class)->times(2)->create(['user_id' => 1]);

3- Setup the Route

Route::apiResource('/users', 'UsersController');

4- Transforming Model into a Resource

/**
* Display a listing of the resource.
*
*
@param User $user
*
@return \Illuminate\Http\Response
*/
public function index(User $user)
{
return new UsersWithPostsResource($user->paginate());
}

5- Users With Posts Resource

<?php

namespace
App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class UsersWithPostsResource extends Resource
{
/**
* Transform the resource into an array.
*
*
@param \Illuminate\Http\Request
*
@return array
*/
public function toArray($request)
{
// Eager load
$this->resource->load('posts');

return $this->resource->map(function ($item) {
return [
'name' => $item->name,
'email' => $item->email,
'posts' => new PostsResource($item->posts)
];
});
}
}

6- Posts Resource

<?php

namespace
App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class PostsResource extends Resource
{
/**
* Transform the resource into an array.
*
*
@param \Illuminate\Http\Request
*
@return array
*/
public function toArray($request)
{
return $this->resource->map(function ($item) {
return [
'title' => $item->title
];
});
}
}

7- Conclusion

The first clear difference when comparing to Fractal is that the resource have easy and direct access to the whole collection instead of a per-object basis. This means that when transforming a collection of Users, you can easily eager load every post without N+1 queries.

It is also easy to nest transformation since you can just spawn a new Resource class that will transform your data as needed.

I expect to write a more detailed post about it once I start digging more into the possibilities.

Followup

This was the first article on API Resources coming to Laravel 5.5. You can find the 2nd article on this subject here: https://medium.com/@deleugpn/reusable-api-resource-with-nested-relationship-laravel-5-5-c654c7243869

More by Marco Aurélio Deleu

Topics of interest

More Related Stories