Laravel is a great framework that is popular among developers and is used for all kinds of projects. One of Laravel's usages is creating APIs.

One asset that you can use to make sure your APIs in Laravel are uniform across requests and the correct desired data is being returned in all APIs is Laravel Resources.

In this tutorial, we'll learn what Laravel Resources are, and how to use them in our Laravel project. You can find the code for this tutorial in this GitHub Repository.

What are Laravel Resources

Laravel Resources are another layer added on top of Laravel Eloquent models. It allows creating a uniform format or shapes for the data returned for these Eloquent models.

Why Use Laravel Resources

It's important to make sure the correct data is being sent in your APIs. For example, you don't want to accidentally send secret data like keys or tokens related to users or other models in your APIs.

Furthermore, when building APIs, it's important that the structure of data is the same across requests. This also helps other developers that might be using your API, as it ensures the data structure across different requests.

Prerequisites

Before we see how we can use Resources in Laravel, we'll first undergo a few commands to set up our Laravel project. If you already have your project set up you can skip this step.

Create Laravel Project

In your terminal, run the following command to create a Laravel project with Composer:

composer create-project laravel/laravel laravel-resources

After the command is done executing, change to the newly created project directory:

cd laravel-resources

Prepare the Database

Next, we'll set up the database. You'll need to make sure you have a MySQL server installed if that's your choice of database.

Setup Database and Connection

We'll create a new database laravel-resources. You can create a database of any name you want.

After you create the database, go to .env and change the configurations related to the database connection:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-resources
DB_USERNAME=root
DB_PASSWORD=

Make sure to place your database name in DB_DATABASE, database username in DB_USERNAME, and database password in DB_PASSWORD.

Changes to Default User Model

In this tutorial, we'll make use of the default User model that comes with every Laravel project. However, we'll make a slight change by adding a new field age.

First, we'll make changes to the migration file. If you're not sure what a migration is, database migrations in Laravel allow defining the database schema easily.

Open database/migrations/2014_10_12_000000_create_users_table.php and add the following line inside Schema::create callback function:

$table->integer('age');

This will add a new age field in the users table.

Next, we'll modify the user factory as we'll use it to create random users. If you're not sure what a factory is, Laravel provides a way to create database records for a model for testing.

Open database/factories/UserFactory.php and inside the definition function add the following at the end of the returned array:

'age' => $this->faker->numberBetween(10, 90)

So, the definition function should look like this:

public function definition()
{
    return [
        'name' => $this->faker->name(),
        'email' => $this->faker->unique()->safeEmail(),
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
        'age' => $this->faker->numberBetween(10, 90)
    ];
}

Finally, we'll make a change to the User model. Open app/Models/User.php and add the age field to the fillable array:

protected $fillable = [
    'name',
    'email',
    'password',
    'age'
];

Create Database Tables

We'll now create the database tables using Laravel's migrations. Run the following command:

php artisan migrate

This will create the users table as well as other tables that come by default in Laravel.

Add Fake Users

Next, we'll utilize the UserFactory to create fake users in our database for testing. Go to database/seeders/DatabaseSeeder.php and uncomment the following line:

// \App\Models\User::factory(10)->create();

Then, run the following command:

php artisan db:seed

And with that, we'll have 10 fake users in our database.

Create a User Resource

Resources are created on top of an eloquent model. This means that typically you'd need a resource for every eloquent model separately.

We'll create a resource for our User model, then see how we can use it in requests.

To create a resource, run the following command:

php artisan make:resource UserResource

This will create a new class UserResource in app/Http/Resources. This is where all Resources that you will create will reside in.

If you open UserResource now, you'll see that there's already a toArray method. This is the method that is used to return the data related to the user. By default, it just returns the result of toArray method on the user.

The current model that the resource is being used for, in this case, it's a user model, is represented inside the resource class by the field resource in the class. So, you can reference the underlying class with $this->resource.

We'll change the returned array of toArray in UserResource to only return the user's id, name, and email. Change the content of toArray to the following:

return [
    'id' => $this->resource->id,
    'name' => $this->resource->name,
    'email' => $this->resource->email
];

Remember, $this->resource refers to an instance of the User model.

We've created our first resource! We'll see it in action in the next section.

Create API Endpoint

In this section, we'll create an API endpoint that allows us to retrieve the data of any user using their ID.

First, we'll create a new controller UserController to handle API requests related to the User model. Run the following command in your terminal:

php artisan make:controller UserController

Then, go to app/Http/Controllers/UserController.php. We'll create a new method getUser that accepts an ID and should return the user's data. Add the following inside the UserController class:

public function getUser($id) {
    $user = User::query()->find($id);

    if (!$user) {
        return response()->json(['success' => false, 'message' => 'User does not exist']);
    }

    return response()->json(['success' => true, 'user' => new UserResource($user)]);
}

We first check that a user with that ID exists. If the user doesn't exist we return a JSON response withsuccess set to false with a message indicating that the user does not exist.

If the user exists, we return a JSON response with success set to true and user set to an instance of UserResource.

Note that to create an instance of a resource, you need to pass it the model the resource should use as a parameter to the constructor like so:

new UserResource($user)

That's all we need to do! We just need to add the new API endpoint as a route.

Open routes/api.php and add the following:

Route::get('/user/{id}', [UserController::class, 'getUser']);

Our API is ready! Time to test it.

Start your server with the following command:

php artisan serve

Then, to test the API endpoint you can use something like Postman or Thunder Client. As this is a GET request without authentication you can also just open the URLs in your browser.

Send a GET request to localhost:8000/api/user/1 or open the URL in your browser. You'll see that the endpoint will return a JSON response with 2 keys, success and user. Notice how the user object includes just the user's id, name, and email which is what we added in our UserResource.

You can try changing the id, which is 1 in the above request, to other IDs and see how it returns the same response structure for all users.

Create a User Collection Resource

Resources are not just for single model instances. You can create a collection resource that takes a collection of model instances as a parameter and formats the collection as necessary.

To create a collection resource for the User model run the following command:

php artisan make:resource UserCollection --collection

This will create the collection resource class at app/Http/Resources/UserCollection.php.

Note that for collection resources there is a naming convention to make sure that the collection is associated with the correct resource model for the instance. The naming convention is <Model>Collection.

So, since our resource name is model name is User the collection resource name will be UserCollection.

If you wish to name the collection differently, you can specify the resource class using the collects field on the collection class:

public $collects = User::class;

Collection resources are similar to singular resources. There is a toArray method that we will use to define the structure of collections.

Change the content of toArray method to the following:

$count = $this->collection->count();

return [
    'count' => $count,
    'data' => $this->collection
];

Note that $this->collection will return an array of objects with the structure the same as defined in UserResource for each user instance in the collection.

Create API Endpoint

We'll now create an API endpoint that will allow us to get all users. In UserController that we created previously add the following method:

public function getUsers () {
    $users = User::query()->get();

    return response()->json(['success' => true, 'users' => new UserCollection($users)]);
}

To create an instance of the collection resource, similar to the singular resource, you need to pass the collection of models as a parameter to the constructor.

Then, add the new route in routes/api.php:

Route::get('/user', [UserController::class, 'getUsers']);

Let's test it. Send a GET request to localhost:8000/api/user or open it in your browser. You'll see that it returns 2 keys success and users. users will be an array of users and all having the same structure as that defined in UserResource.

This shows an example of how defining a Resource guarantees the same structure across requests.

Conditional Fields

Sometimes you might need to add a field based on a condition. To do so, you can use the when method defined on resources.

We'll add an old field that should appear only when the user's age is greater than 18. Add the following field in the returned array in toArray in UserResource:

'old' => $this->when($this->resource->age > 18, true)

This will add the old field only if the user's age is greater than 18. Note that the first paramter of when is the condition and the second parameter is the value expected.

Try sending a GET request to localhost:8000/api/user or open the URL in your browser now. You'll see that some users will have the old field while others don't.

Note that the result for your request will defer as the users generated by the factory are random.

Conclusion

Laravel's API Resources allow making your returned data in APIs structured and uniform. It also guarantees what the fields returned will be so no fields will be accidentally exposed.

You can check out more details about Laravel Resources in their documentation.