Making Api CRUD(Create,Read,Update,Delete) with Laravel 8 n API Authentication with sanctum
Tags: laravel, php
Published: 2021-04-04 18:17:22

Here I am going to mention about how you can make an API with Laravel 8 and Using PostMan. This is inspired from Traversy Medias videos on Laravel APi and Authentication with sanctum [Laravel 8 REST API With Sanctum Authentication](https://www.youtube.com/watch?v=MT-GJQIY3EU&t=2709s). SO you can definitely go and watch that.

#1.Creating a new Laravel project
**laravel new laravel-api-sanctum**
#2.Create a model Product along with Controllers,Seeders,Factory
**php artisan make:model Product -a it creates model,factory,seeder** here its not essential to create Seeders and Factory but I showed this command so that it can help in future development when you need to use seeders and factories.
#3.In Product migrations table
```
$table->id();
$table->string('name');
$table->string('slug');
$table->string('description')->nullable();
$table->decimal('price',5,2);
$table->timestamps();
```
Then run php artisan migrate
#4. API testing and routes api.php 
Usually in Laravel when we use web.php,when we want to make Single Page Application or mobile apps we need api for that we need to use api.php 
in api.php we can write 
```
Route::post('/products', function () {
 
    return Product::create([
        'name'=>'Product One',
         'slug'=>'product-one',
         'description'=>'Details of Product One',
         'price'=>9.99
 
    ]);
    
});

```
Then just go to Product.php and for mass assignment. It is a process through which an array of data will be saved to specific model. Here model is Product 
In Product.php we need to write protected $guarded=[];
In Postman while sending requests we get 
**CREATE**
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x9phe6vwugkuwbjsh29w.png)
This is how we send post requests in POSTMAN 
**READ**
```
public function index(){
  return Product::all();
}
```
This is how we can get all products data in PostMan 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drs1ze5e33n4920tg19k.png)
To send request through Controller in **ProductController.php**
 
Now let us try to make requests through Controller. Here its a Resource Controller 
In api.php
```
Route::post('/products', [ProductController::class,'store']);
```
In ProductController.php 
```
 public function store(Request $request)
    {
        //
       return Product::create($request->all());
    }
```

If we again send get requests to Postman we will get all 3 products
But if we try to insert data without any field it must give us an error
**VALIDATION ERROR**
```
public function store(Request $request)
    {
        //
        $request->validate([
            'name'=>'required',
            'description'=>'required',
            'slug'=>'required',
            'price'=>'required'
 
 
        ]);
       return Product::create($request->all());
    }
```
Get a single product from the route 
Now instead of writing each and every route we can write it in a Resource Controller
Route::resource('products', ProductController::class);

***Update data***
In ProductController.php 
```
  public function update(Request $request,$id)
    {
        //
        $product=Product::find($id);
        $product->update($request->all());
        return $product;
 
    }
```
While we send requests to PostMan for Update this is what it give us 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpf4090hqdow7aoyxjfv.png)
Here we can specify the id we want to update 
**DELETE**
Delete Data
In ProductController.php 
```
public function destroy($id)
    {
        //
        return Product::destroy($id);
    }

```
If we send delete request in Postman we get 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wofrd8u9pgy1n1wmyveu.png)
We are deleting as per id.

**For search**
In ProductController.php
``` 
 public function search($name)
    {
        //
        return Product::where('name','like','%'.$name.'%')->get();
    }
```
In Postman while sending search requests 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6yymm22asymp6g9tuvs.png)

#API Authentication with Sanctum 
Now we are done with API CRUD part we will now enable API authentication with [Sanctum]
(https://laravel.com/docs/8.x/sanctum)
To install Laravel sanctum 
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
In app/Http/Kernel.php 
```
'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
```

In User.php we need to write use use Laravel\Sanctum\HasApiTokens on top and HasAPiTokens below
```
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
     use HasApiTokens, HasFactory, Notifiable;
 ```
In api.php 
Public routes means here anyone can view the products all products or individual products
```
/public routes 
Route::get('/products', [ProductController::class,'index']);
// Route::resource('products', ProductController::class);
Route::get('/products/{id}', [ProductController::class,'show']);

//Protected routes-Only authenticated users can have access to protected routes//
Route::group(['middleware' => ['auth:sanctum']], function () {
     Route::post('/products',[ProductController::class,'store']);
     Route::put('/products/{id}',[ProductController::class,'update']);
     Route::delete('/products/{id}',[ProductController::class,'delete']);
 
 
 });
```
**Auth Controller**
Create a new Controller for Authentication 
php artisan make:controller AuthController

Register method
```
public function register(Request $request){
        $fields=$request->validate([
            'name'=>'required|string',
            'email'=>'required|string|unique:users,email',
            'password'=>'required|string|confirmed'
 
 
        ]);
 
        $user=User::create([
            'name'=>$fields['name'],
            'email'=>$fields['email'],
             'password'=>bcrypt($fields['password'])
 
        ]);
 
        $token=$user->createToken('myapptoken')->plainTextToken;
 
        $response=[
            'user'=>$user,
            'token'=>$token
 
        ];
 
        return response($response,201);
 
    }
```
In api.php 
```
Route::post('/register',[AuthController::class,'register']);

```
In 
api.php 
**Register**
```
Route::post('/register',[AuthController::class,'register']);
```
Testing out in Postman
If we dont give anything it returns us validation errors

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9aq4kmpkhb7im6gug6mu.png)

So here we see upon registration it gives us a token 
Here with help of the token an authenticated user can post,edit and delete
**Now we see it gives us a new token** 
With this token I will be able to gain access to protected routes. If we send post requests we need to use bearer select the bearer token option  token and insert the token

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6bzmbhhfn6i9sjze534i.png)
 While we send post request now we can post data 
Now we need to create Logout function in AuthController.php 
```
 public function logout(Request $request){
        auth()->user()->tokens()->logout();
 
        return [
            'message'=>'Logged out'
        ];
    }
```
In api.php
```
Route::group(['middleware' => ['auth:sanctum']], function () {
     Route::post('/products',[ProductController::class,'store']);
     Route::put('/products/{id}',[ProductController::class,'update']);
     Route::delete('/products/{id}',[ProductController::class,'delete']);
     Route::post('/logout',[AuthController::class,'logout']);
 
 
 });
```
If we now insert the token in bearer token and try to logout 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vj8j6fola7e1ghtzqm1u.png)
We see the message as logged out the token is no longer valid 
Now we can delete,update and post if we are authenticated using that Token