Last updated on February 17, 2018
In this post, I will show how easy it is to use API resources to build REST APIs. In the previous Laravel REST API tutorial, I have used Fractal 3rd party library to control API response data. In Laravel 5.5, we now have API resources and these resources are literally developed based on Fractal.Now we can transform data without Fractal with API resources.
What is Resource
A Resource class is a way to transform data from one format to another. For example, if you have a comment model and you want to manipulate the data or remove certain fields from the model before sending that in our response, it is difficult without using some sort of data transform layers like API API resources or Fractal.
So let’s start your first REST server-
Creating the Laravel app
Create the Laravel app called “todo” with the below command
$ composer create-project laravel/laravel todo --prefer-dist (OR) $ composer create-project laravel/laravel todo 5.5 --prefer-dist
On successful installation, you will get similar output on your console –
$ composer create-project laravel/laravel todo --prefer-dist Installing laravel/laravel (v5.5.0) - Installing laravel/laravel (v5.5.0): Loading from cache Created project in todo > @php -r "file_exists('.env') || copy('.env.example', '.env');" Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 68 installs, 0 updates, 0 removals - Installing vlucas/phpdotenv (v2.4.0): Loading from cache .... ........ phpunit/phpunit suggests installing ext-xdebug (*) Writing lock file Generating autoload files > Illuminate\Foundation\ComposerScripts::postAutoloadDump > @php artisan package:discover Discovered Package: fideloper/proxy Discovered Package: laravel/tinker Package manifest generated successfully. > @php artisan key:generate Application key [base64:SFxdFLndUlDXL04+RcKW6zk0G/oCdA20Efej93fax1g=] set successfully.
Above command will create a todo directory and all project related files and directories will be downloaded into “todo” folder. Now change the directory to todo and issue artisan command to serve the application.
$ cd todo $ php artisan serve
Configure Your Database
Create a database and edit .env
and fill it with your database settings. This article assumes a MySQL database.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_database_name DB_USERNAME=your_username DB_PASSWORD=your_password
Create Migration File
Below command set up the basic migration scripts that we’ll be using to create the database table.
php artisan make:migration create_tasks_table --create=tasks
Now required migration file is in place, so let’s add a table column as shown below.
Edit app/database/migrations/SOME_DATE_create_tasks_table.php
and edit and update the up()
and down()
methods:
public function up() { Schema::create('tasks', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->text('description'); $table->integer('user_id'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('tasks'); }
Add Sample Users and todos
We gonna use Laravel’s seeds to create a few sample users and todos.
Let issue following commands to create seeder class from your root of the project.
php artisan make:seeder UsersTableSeeder php artisan make:seeder TasksTableSeeder
Generated seeders by the above commands will be placed in the database/seeders
directory. In our case, we have two seed files called UsersTableSeeder.php
and TasksTableSeeder.php
.
Update seeder run methods as shown below
UsersTableSeeder.php
public function run() { factory(App\User::class, 50)->create(); }
TasksTableSeeder.php
public function run() { factory(App\Task::class, 50)->create(); }
Next, make sure that seeder class gets run when the database is seeded. Edit app/database/seeds/DatabaseSeeder.php
public function run() { $this->call(UsersTableSeeder::class); $this->call(TasksTableSeeder::class); }
Add Model Factories
Next, create app/database/factories/UserFactory.php
and app/database/factories/TaskFactory.php
and place below code blocks
define(App\User::class, function (Faker $faker) { static $password; return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'password' => $password ?: $password = bcrypt('secret'), 'remember_token' => str_random(10), ]; });
define(App\Task::class, function (Faker $faker) { $users = App\User::pluck('id')->toArray(); return [ 'name' => $faker->unique()->name, 'description' => $faker->text, 'user_id' => $faker->randomElement($users) ]; });
Create Task Model
Laravel comes with a User model setup, so let’s create a model for our tasks table.
Create a modal with
$ php artisan make:model Task
since you are following Laravel naming conventions you don’t have to change anything in the task model.
Run the Migrations
Below are the Laravel’s artisan commands and issue below commands from your project root. These commands will create those tables and inset sample users and tasks to the database.
// Create the tables for migrations $ php artisan migrate // Create the sample users and tasks $ php artisan db:seed
You might get following error –
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
To fix this all you have to do is edit your AppServiceProvider.php
file and inside the boot method set a default string length:
use Illuminate\Support\Facades\Schema; public function boot() { Schema::defaultStringLength(191); }
We gonna build following endpoints –
URL HTTP Method Operation /api/task GET Returns an array of tasks /api/task/:id GET Returns the task with id of :id /api/task POST Adds a new task and return it. /api/task/:id PUT Updates the task with id of :id /api/task/:id DELETE Deletes the task with id of :id
Create Task Controller
$ php artisan make:controller TaskController
Now define your api routes in routes/api.php
// get list of tasks Route::get('tasks','TaskController@index'); // get specific task Route::get('task/{id}','TaskController@show'); // create new task Route::post('task','TaskController@store'); // update existing task Route::put('task','TaskController@store'); // delete a task Route::delete('task/{id}','TaskController@destroy');
Create a Task recource
Now let’s create a resource for Task, which will transform the eloquent model into the proper dataset, which we can return to the end user.
$ php artisan make:resource Task
Above command will generate a file called Task.php
inside app/Http/Resouces
Now update Task.php toArray method with below code -
public function toArray($request) { return [ 'id' => $this->id, 'task' => $this->name, 'task_description' => $this->description ]; }Now let use above generated Task resources inside Task controller -
delete()) { return new TaskResource($task); } } public function store(Request $request) { $task = $request->isMethod('put') ? Task::findOrFail($request->task_id) : new Task; $task->id = $request->input('task_id'); $task->name = $request->input('name'); $task->description = $request->input('description'); $task->user_id = 1; //$request->user()->id; if($task->save()) { return new TaskResource($task); } } }How to access
You can use CURL or any rest client like postman or advanced rest client
Using curl, you could do something like this -
$ curl -H 'content-type: application/json' -v -X GET http://localhost:8000/api/tasks $ curl -H 'content-type: application/json' -v -X GET http://localhost:8000/api/task/:id $ curl -H 'content-type: application/json' -v -X POST -d '{"name":"Test api","description":"I am gonna test apis","user_id":1}' http://localhost:8000/api/task $ curl -H 'content-type: application/json' -v -X PUT -d '{"name":"Test All APIs","description":"I am gonna test apis","user_id":1}}' http://localhost:8000/api/task/:id $ curl -H 'content-type: application/json' -v -X DELETE http://localhost:8000/api/task/:id