Create Secure Laravel 8 RESTful APIs

May 20, 2021

Create Laravel 8 RESTful APIs

In the world of PHP frameworks, many have taken to the scene and become famous, but only a handful remain that can help you out and out with your app-building experience. If you’re planning to build a REST mobile application API, you will need a few prerequisites in addition to basic coding knowledge and familiarity with PHP frameworks.

Though Laravel is an open-source PHP framework, many people hire seasoned developers to work on their projects to get the best possible outcomes. Recently, Laravel 8 comes with new features and Here we will discuss a detailed tutorial to create Laravel 8 RESTful APIs with ease.

What do you need?

To follow this guide with ease, you will require MySQL on your system and some basic PHP framework knowledge for developing apps. Moreover, it would help if you were using either a Linux or a Mac OS. Finally, you also have to understand that Laravel 8 is based on the PHP framework, requiring some knowledge of working with PHP frameworks.

Getting Started

Before you initially get started, Laravel offers you a basic test run so that you can make sure that all the things are running seamlessly and there are no errors. You can go to the applications directory to run this, and all you have to do is enter this code and run it once:

/vendor/bin/phpunit

Once this runs, you have to watch out for everything to be green, indicating that Laravel is running smoothly without any problems.

Ideally, an excellent place to start is first to understand how to build a REST API with Laravel. It is suggested that you begin my MySQL database for a start as this will provide a strong foundation and give you the ease of access as you go on further. Similarly, tp read a specific employee; you can create a similar test.

Before getting into anything else, you can enter the following command in your terminal to run the MySQL client.

$ MySQL -u root -p

Once you’ve entered this code, you can run your MySQL client and, when required, insert your password for the MySQL server accordingly. Next up, you will want to create a database to work with effectively. To do this, run the following command, and you can create your database for a project.

mysql> create database db;

This is a simple command that creates a database for you in MySQL. After you’ve done this, make sure that you update your credentials to access your database. You can even migrate commands here.

You can additionally install a passport on your system via the Composer package manager. Passport generally helps you to create token keys that help with security. Once this is precisely done, you will have to configure your passport accordingly over three places: model, auth config file, and service provider.

You can follow these two codes to do so. There are HasApiTokens for passport, in the model, while in the second code auth.php, there is added API auth configuration to configure the passport for you.

I. models


namespace App\Models;
  
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
  
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
  
    /**
     * The attributes and factors that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
  
    /**
     * The attributes and factors that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = ['password','remember_token'];
  
    /**
     * The attributes and factors that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['email_verified_at' => 'datetime'];

II. config

return [
    .....
    'guards' => [
        'web' => [
            	'driver' => 'session',
           	'provider' => 'users',
	        ],
	        'api' => [
	            'driver' => 'passport',
		    'provider' => 'users',
	        ],
	    ],
	.....
	]

Creating your First Test

Before we begin writing any logic, we start with creating a test. This scenario is one of the starting milestones of creating any test centred coding work. This kind of development ideally requires you to create your test first.

Open this file on your system:

php artisan make: test EmployeeTest

Now that you’ve opened it, you have to make a small change to it. Remove the testExample() line present in it and replace it with this code:

class EmployeeTest extends TestCase
{
    use RefreshDatabase, WithFaker;
}

Now that we have started creating our first test, we will take a step back and understand this test’s function exactly. This first test will help us ‘create’ an employee. Here you can see the basic details of our first test:

public function test_can_create_an_employee() { 
    // make an instance of the Employee Factory
    $employee = Employee::factory()->make([
        'active' => true
    ]);

    // post the data sets to the employees store method
    $response = $this->post(route('employees.store'), [
        'name' => $employee->name,
	'pay_rate' => $employee->pay_rate,
	'job_title' => $employee->job_title,
        'active' => $employee->active
    ]);

   
    $response->assertSuccessful();
    $this->assertDatabaseHas('employees', [
                'name' => $employee->name,
		'pay_rate' => $employee->pay_rate,
		'job_title' => $employee->job_title,
                'active' => $employee->active
    ]); 
}

Let’s break down this test. Foremost, we will call an instance of the Employee factory, but instead of using the create() method, we use the make() method (). We don’t want to write this employee to the database, so we use the make() method instead. We require the values right from the EmployeeFactory, so we use the make() method ().

We place the active => true within the make() function because the factory gets overrides. If you return to the factory, you’ll find that we’ve set it up to pick real or false at random. When true is passed to the make() function, it will always return true.

We then make a POST request to the employee.store, a designated route for which we’ll talk more later.

We then send a precise POST request to the employee.store, a designated route for which we’ll talk more later. The fields that are essential and required to create the employee have been passed into the POST submission.

We then claim that the answer we had was correct and that the employee’s table in the database contains data from the $employee factory we built.

Now when you try to run this test independently, you will get an error displayed. Simply, run the test:

/vendor/bin/phpunit --filter=test_can_create_an_employee

Here’s the error you will see:

There was 1 error:
1) Tests\Feature\EmployeeTest::test_can_create_an_employee
Symfony\Component\Routing\Exception\RouteNotFoundException: Route [employees.store] not defined.
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

This is because our current code doesn’t have a route for employees.store. Now, all we have to do is open up our api.php file, and with this, our code will be much more sorted-

// Employee
Route::resource('employees', EmployeeController::class);

Laravel has a feature where it can easily handle all CRUD functions for standard named routes.

You can find CRUD function methods via HTTP for Laravel. Additionally, the resource controller that Laravel comes with will use additional strategies that can be very useful like a store, update, index and show.

We will not get into the EmployeeController aspect of this, but you can even create a transformer here first if you want.

The Reading Aspect

This is where developing Laravel 8 REST API with Resource Controllers gets interesting. The reading aspect is comparatively easier and does not require a lot of extensive work.

We being by creating a test in our EmployeeTest.php

public function test_can_get_paginated_list_of_all_employees()
{
    // Create 25 Employees in the database
   
    Employee::factory()->count(25)->create();

    // Get all Employees (Paginated)
        $response = $this->get(route('employees.index'));
        $response->assertSuccessful();

   	$response->assertJsonStructure([
        'data' => [
            '*' => [
               	'id',
		'name',
		'job_title',
		'pay_rate',
		'active',
		'deleted_at',
		'created_at',
		'updated_at',
            ]
        ],
        'links' => [               
		‘first’,
		‘last’,
		'prev',
		'next',
        ],
        'meta' => [               
		"current_page",					               
		"from",					               
		"path",					               
		"per_page",					               
		"to",					               
		“success”,					               
		"message",
        ]
    ]);
}

Here, we are giving back the collection of the EmployeeResource and instead of passing in the Employee Model by using a simplepaginate trait. Here, we also change the assigned default limit of URL Param to 15 unless it is specifically mentioned to be something else.

You can use the URL of this request by entering:
GET: api/employees?paginate=15
Now you have to run the test for this code:

/vendor/bin/phpunit --filter=test_can_get_paginated_list_of_all_employees

The result will be all green.

To read a specific employee; instead, you can create a similar custom test. This one would be very similar to the test we just used, with the difference being that we give the value $ employee out directly to the factory where the database stored the value employee. The following URL of this would hence be-

Route: employees.show
URI: api/employees/{employee}
Method: GET
Update
The update is very similar to the store/create, except for some other minor changes. We can first create a test:<

public function test_can_update_an_employee()  
{  
    $employee = Employee::factory()->create([  
            'active' => true  
  	]);  
 
    $response = $this->patch(route('employees.update', $employee->id), [  
        'name' => $name = $this->faker->name,  
        'job_title' => $job_title = $this->faker->jobTitle,  
        'pay_rate' => $pay_rate = $this->faker->randomFloat(2, 10, 20),  
        'active' => false  
  	]);  
 
$response->assertSuccessful(); 
   
$this->assertDatabaseHas('employees', [  
        'id' => $employee->id,  
        'name' => $name,  
        'job_title' => $job_title,  
        'pay_rate' => $pay_rate,  
        'active' => false  
  ]);  
}

Though similar, this test is actually different wherein Employee: :factory() is used to create an employee and then a patch request is performed to the URL that is employees/{employee}

Here we now begin passing new data with new data assigned to the variables. Now on our controller i.e the EmployeeController we will get started on an update() method like this:

/**  
 * Update the specified resource in storage. * * @param Request $request  
 * @param Employee $employee  
 * @return JsonResponse|EmployeeResource  
*/
public function update(Request $request, Employee $employee) 
{  
    $validator = Validator::make($request->all(), [  
        'name' => 'sometimes|required|string',  
        'pay_rate' => 'sometimes|required|numeric',  
        'job_title' => 'sometimes|required|string',  
        'active' => 'sometimes|required|boolean',  
    ]);  
 
    if ($validator->fails()) {  
        return response()->json($validator->errors()->toArray(), 422);  
    }  
    DB::beginTransaction();  
    try {  
	$updated_employee = EmployeeTransformer::toInstance($validator->validate(), $employee);  
        $updated_employee->save();  
       	DB::commit();  
    } catch (Exception $ex) {  
       	Log::info($ex->getMessage());  
       	DB::rollBack();  
        return response()->json($ex->getMessage(), 409); 
    }  
 	return (new EmployeeResource($updated_employee))  
	->additional(['meta' => ['success' => true,'message' => "employee updated"]]);  
}

Here, $updated_employee is the latest version of $ employee, and it has newly updated data to it. We save this and return the data to EmployeeResource.

You can run a test to confirm that updating an employee works with this:

/vendor/bin/phpunit --filter=test_can_update_an_employee

And you’ll see green once again. This is all you require to know about the Laravel 8 REST API CRUD functions.

Delete

Most developers you’ll come across prefer soft deleting as this doesn’t entirely get rid of your data sets, and you can explicitly recover it as and when needed. Even if you don’t prefer soft deletes, you’ll find that the method for the rest of this controller is very similar so let’s look at our first test here:

public function test_can_delete_an_employee()  
{  
    $employee = Employee::factory()->create([  
             'active' => true  
  	]);  
    $response = $this->delete(route('employees.destroy', $employee->id));  
   
	$response->assertSuccessful(); 
   
	$this->assertSoftDeleted('employees', [  
        'id' => $employee->id,  
        'active' => false  
  	]);  
}

In this simple test, we assert the database to say that it is soft deleted. Now we move back to the EmployeeController and use a destroy() method:

/**  
 * Remove the specified resource from storage. 
 * @param Employee $ employee  
 * @return JsonResponse  
 */
public function destroy(Employee $employee)  
{  
    DB::beginTransaction();  
    try {  
    	$employee->delete();  
    	$employee->active = false;  
       	$employee->save();  
       	DB::commit();  
    } catch (Exception $ex) {  
       	Log::info($ex->getMessage());  
       	DB::rollBack();  
        return response()->json($ex->getMessage(), 409); 
    }   
    return response()->json('employee has been deleted', 204);   
}

If you need to recover this data still somehow, there are ways that you can find it, but that’s for another day. You can test the entire folder here with:

/vendor/bin/phpunit --filter=EmployeeTest

Key Takeaways

That’s all there is to it. While using Laravel can be intimidating and a little complex. However, as you get used to it, you’ll find it much easier to work on than other platforms out there. So now you know how to make a RESTful API in Laravel 8.

We at Laravel development company india have an experienced team of Laravel developers who have in- depth knowledge in this new version.

Be sure to keep exploring LDCI for more complex work, as we have a lot of experience in complex and enterprise level laravel application development on an industrial scale and you can connect with our teams for your upcoming technology projects.

LDCI Written By: Kosha Shah

Leave a

Comment

Your email address will not be published. Required fields are marked *