How to Create a Secure CRUD RESTful API in Laravel 8 and 7 Using Laravel Passport
Tags: php, laravel, webdev, beginners
Published: 2020-10-15 13:21:35

Good day, today we are going to be coding strictly in the backend, we are going to convert our [Laravel 8 CRUD](https://dev.to/kingsconsult/laravel-8-crud-bi9) app to RESTful APIs. API is a software intermediary that allows two applications to talk to each other. Somethings you might need to create an app that can be run on different languages or frameworks, for example, you can use Laravel to create the backend for your application while the frontend might run on any JavaScript frameworks. API allows two or more programs to communicate with each other.
There are different types of APIs, but today we are going to concentrate on **RESTful APIs**. **REST** stands for **Representational State Transfer**, while **API** stands for **Application Programming Interface**. You can read more about API  from the internet or other programming material.

Click on my [profile](https://dev.to/kingsconsult) to follow me to get more updates.

Normally, when we build an application, we need to secure the application so that unauthorized access will be blocked. Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? API does not maintain a session state between requests, so there is a need to use tokens to authenticate the app and also authorize the usage of the app.
Laravel provided a package that makes authentication of API very easy by using Laravel Passport, though, there are other options, this is the official packages by the Laravel team, this package provides a full OAuth2 server implementation. It is easy to apply and can be achieved in minutes. Without saying much, let's dive into it.
### **STEP 1: install laravel 8**
To install the latest laravel framework, which is laravel 8.0 as of the time of publishing this article, run the command below
> composer create-project --prefer-dist laravel/laravel laravel_8_api_crud

This will automatically create a laravel 8 app and some couple of things have been set up, we don’t need to copy and rename the env.example file, Laravel 8 does that automatically for us
![alt text](https://res.cloudinary.com/kingsconsult/image/upload/v1599620098/2_hsdqkq.png)
Another important thing about Laravel 8, you don’t need to generate APP_KEY, this new version will also generate it for us.
![alt text](https://res.cloudinary.com/kingsconsult/image/upload/v1599620098/3_fwdwkq.png)
With that all set up, our app is ready.
### **Step 2: Database setup**
Create an empty database, Open the .env file, and update your database configurations. 
![alt text](https://res.cloudinary.com/kingsconsult/image/upload/v1602754638/laravel%208%20api%20crud/2_tnuaxp.png)
For more information on this step, you can visit my previous article, where I explained the steps very well, [Laravel 8 CRUD](https://dev.to/kingsconsult/laravel-8-crud-bi9).
### **Step 3: Install Laravel Passport**
let us install Laravel Passport, Passport service provider registers its own database migration directory, this means that it creates the table that we will be needing for storing clients. The table will be used to store the token generated which will be used to identify a currently authenticated user. This token will then be attached to every request allowing each user access to protected routes.
> composer require laravel/passport

![install Laravel/passport](https://res.cloudinary.com/kingsconsult/image/upload/v1602754638/laravel%208%20api%20crud/1_lefur7.png)
After installation, then we need to migrate, but before we run our migration command, we need to specify the default string length, else, we are going to run into errors. So go to **app/Providers/AppServiceProvider.php** and add this to the boot function
> **Schema::defaultstringLength(191);**

also, add this to the top of the class
> **use Illuminate\Support\Facades\Schema;**

![alt text](https://res.cloudinary.com/kingsconsult/image/upload/v1599620099/8_oqufma.png)
Finally, we run our migration command
> **php artisan migrate**

![migrations](https://res.cloudinary.com/kingsconsult/image/upload/v1602754639/laravel%208%20api%20crud/3_ktfadd.png)

### **Step 4: Create the encryption keys**
We need to create the encryption keys that are needed to generate our secure access tokens.
> php artisan passport:install

This command will also create "personal access" and "password grant" clients which will be used to generate access tokens.
![install passport](https://res.cloudinary.com/kingsconsult/image/upload/v1602754638/laravel%208%20api%20crud/4_fjxgua.png)
### **Step 5: Add the HasApiTokens trait to our user model**
Go to **App\Models\User.php** and tell the User class to 
> **use HasApiTokens**,

Also add this to the top
> **use Laravel\Passport\HasApiTokens;**

![User Model](https://res.cloudinary.com/kingsconsult/image/upload/v1602754639/laravel%208%20api%20crud/5_dkojfu.png)
#### **Step 6: Call the passport routes in AuthServiceProvider**
Go to **App/Providers/AuthServiceProvider.php** and add 
> **Passport::routes();**

To the boot method, also add the path before the class at the top
> **use Laravel\Passport\Passport;**

Uncomment the policy in the protected method of $policies
![AuthServiceProvider](https://res.cloudinary.com/kingsconsult/image/upload/v1602758127/laravel%208%20api%20crud/6_nrbrzf.png)
### **Step 7: Set the driver**
This will be the final step in the setting up and configuration of Laravel\Passport, we going to change our **api** driver from the default token to passport.
Go to **config\auth.php** and locate the **guards** array. In the api key, change the driver from token to passport 
![auth config](https://res.cloudinary.com/kingsconsult/image/upload/v1602754638/laravel%208%20api%20crud/7_hrrpip.png)
### **Step 8: Create the Migration file for our CRUD api project**
> php artisan make:model Project -m

![make migration](https://res.cloudinary.com/kingsconsult/image/upload/v1602754639/laravel%208%20api%20crud/8_kmozgi.png)
A migration file will be created in the **database/migrations** folder, and we need to create our schema, I added name (string), introduction (string), location (string), cost of the project (integer).
```
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateProjectsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('projects', function (Blueprint $table) {
            $table->id();
            $table->string('name', 255);
            $table->string('introduction', 500)->nullable();
            $table->string('location', 255)->nullable();
            $table->integer('cost')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('projects');
    }
}
```
We need to update our Project Model so that it can be able to accept the fields. We need to add a protected $fillable method that will contain the fields that a user of the app can fill, this helps to prevent someone from hacking into the app through input fields.
```
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    use HasFactory;
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'location',
        'introduction',
        'cost',
    ];


    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'cost' => 'int',
    ];
}
```
### **Step 9: Migrate the new table**
![migration](https://res.cloudinary.com/kingsconsult/image/upload/v1602754639/laravel%208%20api%20crud/9_bjf7gi.png)
### **Step 10: Create a Resource**
When building an API, the response will always be in JSON format, so we need a transformation layer that sits between our Eloquent models and the JSON responses. This is what will serve the response to the application’s user in a JSON format. Laravel provides us with a resource class that will help in transforming our models and the model collections into JSON. So we are going to create that 
> php artisan make:resource ProjectResource

This will create a folder in the **app** directory called Resources and also a file **ProjectResource.php** inside the resources.
![create Project Resource](https://res.cloudinary.com/kingsconsult/image/upload/v1602754639/laravel%208%20api%20crud/10_mxeklr.png)      
### **Step 11: Create our Controllers**
The Controller is responsible for the direction of the flow of data and an interface between the user and the database and views. In this case, we are not interacting with views now because we are dealing with API, so our response will be in JSON format. The standard for RESTful APIs is to send the response in JSON. 
We are going to be creating two controllers, the first will be the Authentication Controller and the second is our Project Controller, we need the Authentication Controller in order to generate the token to use in Project Controller.
> php artisan make:controller API/AuthController

This will create a folder called API in **App/Http/Controllers**. It will also create a new file called **AuthController.php**. Click on **AuthController.php** and update it with the following code.
```
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;



class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|max:55',
            'email' => 'email|required|unique:users',
            'password' => 'required|confirmed'
        ]);

        $validatedData['password'] = Hash::make($request->password);

        $user = User::create($validatedData);

        $accessToken = $user->createToken('authToken')->accessToken;

        return response(['user' => $user, 'access_token' => $accessToken], 201);
    }

    public function login(Request $request)
    {
        $loginData = $request->validate([
            'email' => 'email|required',
            'password' => 'required'
        ]);

        if (!auth()->attempt($loginData)) {
            return response(['message' => 'This User does not exist, check your details'], 400);
        }

        $accessToken = auth()->user()->createToken('authToken')->accessToken;

        return response(['user' => auth()->user(), 'access_token' => $accessToken]);
    }
}
```
In our AuthController, we created two methods: register and logic methods
In the register method, we use the Laravel Validate method to make sure that the name, email, and password is provided, this will also make sure that the email has not been taken and is a valid email address, the password must be confirmed before the user will be added. 

After the validation, we use hash to encrypt the password before creating the user, we can't store plain password, lastly, we grab the access token and return it with the user’s information.
In the login method, we also validate the data been pass, to make sure the email and password are submitted, if the data did not correspond to any user, it will return a message that the user does not exist, if it corresponds, then it returns the user and the access token.

Let us create our ProjectController in the API using **--api** switch.
> php artisan make:controller API/ProjectController --api --model=Project

The --api switch will create our Controller without the create and edit methods, those methods will present HTML templates.
Go to **App/Http/Controller/API**, and click on ProjectController, copy the code below and update the methods.  
```
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Project;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\ProjectResource;

class ProjectController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $projects = Project::all();
        return response([ 'projects' => ProjectResource::collection($projects), 'message' => 'Retrieved successfully'], 200);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $data = $request->all();

        $validator = Validator::make($data, [
            'name' => 'required|max:255',
            'description' => 'required|max:255',
            'cost' => 'required'
        ]);

        if ($validator->fails()) {
            return response(['error' => $validator->errors(), 'Validation Error']);
        }

        $project = Project::create($data);

        return response(['project' => new ProjectResource($project), 'message' => 'Created successfully'], 201);
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Project  $project
     * @return \Illuminate\Http\Response
     */
    public function show(Project $project)
    {
        return response(['project' => new ProjectResource($project), 'message' => 'Retrieved successfully'], 200);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Project  $project
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Project $project)
    {
        $project->update($request->all());

        return response(['project' => new ProjectResource($project), 'message' => 'Update successfully'], 200);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Project  $project
     * @return \Illuminate\Http\Response
     */
    public function destroy(Project $project)
    {
        $project->delete();

        return response(['message' => 'Deleted']);
    }
}
```
1. The **index** method will retrieve all the projects in the database with a success message (Retrieved successfully) and returns a status code of 200.
2. The **store** method will validate and store a new project, just like the AuthController, and returns a status code of 201, also a message of "Created successfully".
3. The **show** method will retrieve just one project that was passed through the implicit route model binding, and also returns an HTTP code of 200 if successful.
4. The **update** method receives the HTTP request and the particular item that needs to be edited as a parameter. It updates the project and returns the appropriate response. 
5. The **destroy** method also receives a particular project through implicit route model binding and deletes it from the database.
 
### **Step 12: Create our Routes**
Go to routes folder and click on api.php, and updates with the following code
```
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\ProjectController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});


Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);

Route::apiResource('projects', ProjectController::class)->middleware('auth:api');
```
We added a register route and login routes which are post routes and also an apiResource route for projects utilizing the auth:api middleware.
### **Step 13: Testing**
We are going to be testing our API with Postman, due to complexity and time, I might not be able to explain everything on Postman, but observe the red squares on this page
![postman](https://res.cloudinary.com/kingsconsult/image/upload/v1602766051/laravel%208%20api%20crud/23_nppyj6.png)
**register a user**
![register route](https://res.cloudinary.com/kingsconsult/image/upload/v1602764462/laravel%208%20api%20crud/12_ehbzjo.png)
**trying to get a user that does not exist**
![User not found](https://res.cloudinary.com/kingsconsult/image/upload/v1602764461/laravel%208%20api%20crud/13_klw0by.png)
**Login a registered user**
![Login successful](https://res.cloudinary.com/kingsconsult/image/upload/v1602764462/laravel%208%20api%20crud/14_its2nu.png)
In other to access the projects routes, we must authenticate the user, in other to achieve this, we must add the user's token.
Copy the access token generated for the user when the user login in, click on **Authorization** on postman and select the type, **Bearer Token**, and paste the token by the input field by the right. 
![access token](https://res.cloudinary.com/kingsconsult/image/upload/v1602764460/laravel%208%20api%20crud/16_lugpfr.png)
**Retrieve all the projects, but no project was created**
![empty database](https://res.cloudinary.com/kingsconsult/image/upload/v1602764460/laravel%208%20api%20crud/15_qqm35r.png)
**Create a project**
![post a project](https://res.cloudinary.com/kingsconsult/image/upload/v1602764460/laravel%208%20api%20crud/17_n29i1m.png)
**Retrieve all the projects**
![All projects](https://res.cloudinary.com/kingsconsult/image/upload/v1602764460/laravel%208%20api%20crud/18_iuithh.png)
**Retrieve just 1 project**
![One project](https://res.cloudinary.com/kingsconsult/image/upload/v1602764460/laravel%208%20api%20crud/19_pzdbep.png)
**Update a project**
![Update](https://res.cloudinary.com/kingsconsult/image/upload/v1602764463/laravel%208%20api%20crud/21_bn94lb.png)
**Delete a project**
![Delete](https://res.cloudinary.com/kingsconsult/image/upload/v1602764461/laravel%208%20api%20crud/22_fpda9a.png)

Finally, we have come to the end of the article, if you follow the article religiously, you will not make a mistake, but in case you can't follow all through, this is the link to the [repo](https://github.com/Kingsconsult/laravel_8_API_CRUD)

You can encourage me by clicking the heart button to show love, you are can also leave a comment, suggestion, etc. You are also free to contact me through any of my contact details.

 [click the link to view my profile and follow me] (https://dev.to/kingsconsult)

Visit my other posts 
{% link https://dev.to/kingsconsult/how-to-send-email-in-laravel-8-downwards-using-gmail-3hid %}
{% link https://dev.to/kingsconsult/how-to-upload-data-with-excel-sheet-in-laravel-8-and-laravel-7-3515 %}