Restful API is one of the powerful term which help us to use different set of data formats that helps to drive an extensive business. To make a move with that, today we are planning to write on the right way of building and testing Laravel RESTful API. Before that, let’s understand what RESTful APIs are and what its exact impact on web services today.
So basically, what is Restful API?
While REST stands for Representational State Transfer. RESTful API is an application programming interface which relies mainly on stateless protocol like HTTP for interaction. In RESTful APIs, we are using HTTP verbs like GET, POST, PUT and DELETE as actions and endpoints are the resources acted upon.
How To Set Up A Laravel Project
We can use composer to install and handle all the dependencies. First, install Laravel using the following command,
composer global require laravel/installer
Here I am using following command to create a new project using Composer.
composer create-project --prefer-dist laravel/laravel testapp
Since Laravel is already installed, you need to start the server and test to ensure that everything works fine.
php artisan serve
After starting the server, if you open http://localhost:8000 on the browser, the default page will be loaded.
Tips And Tricks: Best Laravel Security Practices You Must Try It Out!
Models And Migrations In Laravel
Before writing scripts for migrations, we have to ensure that you have created database for the application and whether its details are added to the .env file in the root of the project or not and if not please add.
Let’s start with creating model and migration for Product. The product should have name and description. You can use Laravel’s artisan commands to create migrations and models. You can use following command to create the Product model.
php artisan make:model Product –m
The -m in the above command is for migration. It tells Artisan to create a migration file for our model. The migration file is as follows,
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProductsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('products'); } }
We can update the up() method by adding two more lines like below.
public function up() { Schema::create('product', function (Blueprint $table) { $table->increments('id'); $table->string(‘name’); $table->text('description'); $table->timestamps(); }); }
So its time to run the migration. You can use the following artisan command to run the migration.
php artisan migrate
After running the migration, by default laravel comes with two migration files create_users_table and create_password_resets_table.
Now we can consider our model Product and add its attributes to $fillable field. The fields inside $fillable property are said to be mass assigned and it will be done using eloquent’s create and update method.
Related: How To Create A Custom Validation Rule In Laravel
Database Seeding In Laravel
Database seeding is the process of adding dummy data to the database which we can use for testing purpose. Laravel has a package called Faker, using this we can generate dummy data. Here we are creating two seeder classes. One for Products and other for Users. Use the following artisan command to create the Product seeder class.
php artisan make:seeder ProductsTableSeeder
Running the above command will result in following class,
class ProductsTableSeeder extends Seeder { public function run() { // Let's truncate our existing records to start from scratch. Product::truncate(); $faker = \Faker\Factory::create(); // And now, let's create a few products in our database: for ($i = 0; $i < 50; $i++) { Product::create([ 'name' => $faker->sentence, 'description' => $faker->paragraph, ]); } } }
Similarly create users Seeder class as follows:
class UsersTableSeeder extends Seeder { public function run() { // Let's clear the users table first User::truncate(); $faker = \Faker\Factory::create(); $password = Hash::make('test123'); User::create([ 'name' => 'Administrator', 'email' => 'admin@test.com', 'password' => $password, ]); // And now let's generate a few dozen users for our app: for ($i = 0; $i < 10; $i++) { User::create([ 'name' => $faker->name, 'email' => $faker->email, 'password' => $password, ]); } } }
Then we need to add these two seeders to main DatabaseSeeder class and run
class DatabaseSeeder extends Seeder { public function run() { $this->call(ProducstTableSeeder::class); $this->call(UsersTableSeeder::class); } }
After adding these, if we run the following artisan command,
php artisan db:seed
It will successfully run all the seeder classes and it will complete the seeding process too.
Now , let’s create controller and create all the basic functions inside the controller. The controller can be created by following command.
php artisan make:controller ProductController
class ProductController extends Controller { public function index() { return Product::all(); } public function show(Product $product) { return $product; } public function store(Request $request) { $product = Product::create($request->all()); return response()->json($product); } public function update(Request $request, Product $product) { $product ->update($request->all()); return response()->json($product); } public function delete(Product $product) { $product ->delete(); return response()->json(null); } }
We created controller and filled it with all the basic actions that we required. Now we need to check how the endpoints will looks inside routes/api file. In this case for endpoints we have used implicit route model binding.
Route::get('products', 'ProductController@index'); Route::post('products', 'ProductController@store'); Route::get('products/{product}', 'ProductController@show'); Route::put('products/{product}', 'ProductController@update'); Route::delete('products/{product}', 'ProductController@delete');
API Authentication In Laravel
API authentication in Laravel can be implemented by several ways. Here we are following one simple approach that we have to add an extra field token_api to the users table. For that we need to create migration file as follows.
php artisan make:migration --table=users add_token_api_to_users_table
public function up() { Schema::table('users', function (Blueprint $table) { $table->string('token_api', 60)->unique()->nullable(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn(['token_api']); }); }
Once we run this following command then automatically the new field will be added,
php artisan migrate
Testing the APIs
Now we can jump into another important part. Testing the API endpoints that we created. There are several tools available to test your API, but Laravel has PHPUnit integration in which they are already set up phpunit.xml. We are following this method. In this case we are using SQLite database which is very fast. But it also has some drawback that, some migration commands may not work but it will not affect us much. So, here our plan is to run migration for each test, so we have to create database for each test and destroy it.
Some configuration change also needs to be done. Inside config/database.php, change the database field in the sqlite configuration to ‘:memory:’. Similarly we have to enable SQLite in phpunit.xml by adding the following env variable
<env name="DB_CONNECTION" value="sqlite"/>
We have to configure the base Testcase class to run the migrations and seed db before doing each test.
The class should be like this
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; use Illuminate\Support\Facades\Artisan; abstract class TestCase extends BaseTestCase { use CreatesApplication, DatabaseMigrations; public function setUp() { parent::setUp(); Artisan::call('db:seed'); } }
Last but the least! ensure to add the test command to composer.json before running the test.
"scripts": { "test" : [ "vendor/bin/phpunit" ], },
This will help us to run the test command like below,
composer test
You can test the Product endpoints as below
class ProductTest extends TestCase { public function testsProductsCreation() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => "Bearer $token"]; $payload = [ 'name' => 'Test', 'description' => 'Sample description', ]; $this->json('POST', '/api/products', $payload, $headers) ->assertStatus(200) ->assertJson(['id' => 1, 'name' => 'Test', 'description' => ' Sample description ']); } public function testsProductsUpdate() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => "Bearer $token"]; $product = factory(Product::class)->create([ 'name' => 'Product name one', 'description' => 'Product description one', ]); $payload = [ 'name' => 'Test', 'description' => 'Sample description', ]; $response = $this->json('PUT', '/api/products/' . $product->id, $payload, $headers) ->assertStatus(200) ->assertJson([ 'id' => 1, 'name' => 'Test', 'description' => 'Sample description' ]); } public function testsProductsDelete() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => "Bearer $token"]; $product = factory(Product::class)->create([ 'name' => 'Product name one', 'description' => 'Product description one', ]); $this->json('DELETE', '/api/products/' . $product->id, [], $headers) ->assertStatus(204); } public function testProductsList() { factory(Product::class)->create([ 'name' => 'Product name one', 'description' => 'Product description one' ]); factory(Product::class)->create([ 'name' => 'Product name two', 'description' => 'Product description two' ]); $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => "Bearer $token"]; $response = $this->json('GET', '/api/products', [], $headers) ->assertStatus(200) ->assertJson([ [ 'name' => 'Product name one',, 'decription' => 'Product description one'], [ 'name' => 'Product name two', 'description' => 'Product description two] ]) ->assertJsonStructure([ '*' => ['id', 'name', 'description', 'created_at', 'updated_at'], ]); } }
That’s great! we’re successfully done with building and testing Laravel API, Now what we have seen is the basic and most required steps for creating any Laravel Restful API and eventually will see more on implementing more authenticated techniques like laravel Passport on our next blog. And if you’re the entrepreneur trying to build highly secured site in Laravel or any PHP frameworks then don’t miss the chance to talk with our highly skilled experts who expertise in building highly functional sites. Get in touch with our experts to proof of concept.