Mini App Using Laravel Rest API Only ( back-end ) and Insomnia
Published: 2023-05-09 15:47:30

in this tutorial we are going to create a mini full stack application using laravel for back-end as a CRUD REST API and Angular for front-end .

## required tools for this application

- WampServer or XAMPP for using Apache and MySQL for our Database

- Download the Composer installer for Windows

after Runing the installer, it will set up Composer globally on your system.

https://getcomposer.org/download/


```javascript
composer global require laravel/installer
```
there is two way to install laravel project in our machine ,
Run the following command to create a new Laravel project:

```javascript
laravel new my-laravel-api
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4i1fwfb19hn1cgaj8efs.png)
final results should look like this : 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcgwg6gdm09srcyml8jr.png)



 or we can install laravel with Composer 

```javascript
composer create-project  laravel/laravel my-laravel-api
```
if you want to install specific version there is so many Syntax , this is the most popular : 

```php
composer create-project laravel/laravel=7.4 my-laravel-api
```

Installation Steps

```cmd
cd my-laravel-api
```

**Installation  Sanctum   : **

> 
Laravel Sanctum is a lightweight package for Laravel that enables token-based authentication for APIs. It simplifies the process of generating, managing, and authenticating tokens, providing a secure way to protect API endpoints.

1. installing sanctum

```javascript
composer require laravel/sanctum
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amvokiznalcd0digxc7g.png)



 After successfully install package, we need to publish configuration file with following command :

> The above command will create a create_personal_access_tokens_table.php in your /database/migrations folder and a sanctum.php file inside the /config folder, once you have verified the creation of those two files, the next thing to do is to migrate the new migration file, and you do that with the following command:

```javascript
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
```




create migration for data : 

```php
php artisan make:migration create_posts_table 
```

replace your migration in posts with any column you want to add: 

```javascript
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->longText('description');
            $table->timestamps();
        });
    }
```

or we can create student model and migration with same command line 

creating our model with migration file: 

```php
php artisan make:model Post -m
```

updating our model with this lines : 

```php
class Post extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'description'];
}
```

now we should create a database manually in mysql and add it to the . env file :


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghsynw9993x1f01tpzs5.png)

```php
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tplaravel
DB_USERNAME=root
DB_PASSWORD=
```



we require to get default migration for create new sanctum tables and posts in our database. so let's run bellow command.

```php
php artisan migrate
```

the result should look like this : 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16pzns7rcjzhig16tix5.png)

2. Create sancthum Auth and CRUD Controller

```php
php artisan make:controller Api\AuthController
php artisan make:controller Api\PostController --model=Post
```

Now update AuthContoller with


```php
<?php

namespace App\Http\Controllers\Api;

use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Sanctum\PersonalAccessToken;
class AuthController extends Controller
{
    /**
     * Create User
     * @param Request $request
     * @return User 
     */
    public function createUser(Request $request)
    {
        try {
            //Validated
            $validateUser = Validator::make(
                $request->all(),
                [
                    'name' => 'required',
                    'email' => 'required|email|unique:users,email',
                    'password' => 'required'
                ]
            );

            if ($validateUser->fails()) {
                return response()->json([
                    'status' => false,
                    'message' => 'validation error',
                    'errors' => $validateUser->errors()
                ], 401);
            }

            $user = User::create([
                'name' => $request->name,
                'email' => $request->email,
                'password' => Hash::make($request->password)
            ]);

            return response()->json([
                'status' => true,
                'message' => 'User Created Successfully',
                'token' => $user->createToken("API TOKEN")->plainTextToken
            ], 200);
        } catch (\Throwable $th) {
            return response()->json([
                'status' => false,
                'message' => $th->getMessage()
            ], 500);
        }
    }

    /**
     * Login The User
     * @param Request $request
     * @return User
     */
    public function loginUser(Request $request)
    {
        try {
            $validateUser = Validator::make(
                $request->all(),
                [
                    'email' => 'required|email',
                    'password' => 'required'
                ]
            );

            if ($validateUser->fails()) {
                return response()->json([
                    'status' => false,
                    'message' => 'validation error',
                    'errors' => $validateUser->errors()
                ], 401);
            }

            if (!Auth::attempt($request->only(['email', 'password']))) {
                return response()->json([
                    'status' => false,
                    'message' => 'Email & Password does not match with our record.',
                ], 401);
            }

            $user = User::where('email', $request->email)->first();

            return response()->json([
                'status' => true,
                'message' => 'User Logged In Successfully',
                'token' => $user->createToken("API TOKEN")->plainTextToken
            ], 200);
        } catch (\Throwable $th) {
            return response()->json([
                'status' => false,
                'message' => $th->getMessage()
            ], 500);
        }
    }

public function logoutUser(Request $request)
    {
     // Get bearer token from the request
        $accessToken = $request->bearerToken();

        // Get access token from database
        $token = PersonalAccessToken::findToken($accessToken);

        // Revoke token
        $token->delete();
        return [
            'message' => 'user logged out'
        ];
    }


}

```



custumize message for not login users : 

first step go to Middleware/Authenticate.php

```javascript
use Illuminate\Auth\AuthenticationException;

// replace your redirect method by this one : 


    protected function redirectTo($request)
    {
        if ($request->expectsJson()) {
            throw new AuthenticationException('Unauthenticated.');
        }

        return response()->json(['valid' => auth()->check()]);
    }

```

To change the "Route [login] not defined" error message in Laravel Sanctum's controller, you can modify the app/Exceptions/Handler.php file. Follow these steps:

Open the app/Exceptions/Handler.php file.

Inside the render method, add the following code:

```javascript
use Illuminate\Auth\AuthenticationException;
use Illuminate\Validation\ValidationException;

  public function render($request, Throwable $exception)
        {
        if ($exception instanceof AuthenticationException) {
            return response()->json(['message' => 'you are not logged'], 401);
        }


        return parent::render($request, $exception);
    }
```


![not logged](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/if3i8cn4lye6zjrokf0y.png)



and update your PostController : 

```php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();

        return response()->json([
            'status' => true,
            'posts' => $posts
        ]);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    // store one post with our request post api { "title" : "test","description":"details"}
    // public function store(Request $request)
    // {
    //     $post = Post::create($request->all());

    //     return response()->json([
    //         'status' => true,
    //         'message' => "Post Created successfully!",
    //         'post' => $post
    //     ], 200);
    // }

    public function store(Request $request)
    {
        $postsData = $request->all();

        $posts = [];

        foreach ($postsData as $postData) {
            $post = Post::create($postData);
            $posts[] = $post;
        }

        return response()->json([
            'status' => true,
            'posts' => $posts
        ], 201);
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);

        if (!$post) {
            return response()->json([
                'status' => false,
                'message' => 'Post not found'
            ], 404);
        }

        return response()->json([
            'status' => true,
            'post' => $post
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function edit(Post $post)
    {
        //
    }

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

        return response()->json([
            'status' => true,
            'message' => "Post Updated successfully!",
            'post' => $post
        ], 200);
    }

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

        return response()->json([
            'status' => true,
            'message' => "Post Deleted successfully!",
        ], 200);
    }
}

```


```
php artisan route:clear
```
In routes\api.php file update the API

> In Laravel, the Route::apiResource() method is used to define a set of RESTful API routes for a resource. In this case, the resource being defined is posts, and it is associated with the PostController class.

The apiResource() method automatically generates the following routes for the posts resource:

GET /posts: get lists of all posts.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1200705dwaxmrdfsypw.png)



POST /posts: Creates a new post.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w81nh0xbnbvjysr5vuzc.png)



GET /posts/{id}: Retrieves a specific post by its ID.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dq98yhv7e2tjny5xzj38.png)




PUT /posts/{id}: Updates a specific post by its ID.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lhj4rvjnk15pk29bx93p.png)


DELETE /posts/{id}: Deletes a specific post by its ID.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/614e0xc6xwyumalx5t9v.png)

PATCH /posts/{id}:Updates a specific column in a post by its ID.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64di1xd8cun6dq91gwv7.png)

dont forget to add Bearer <token> in your curl or header options after login or register for every action you want to call because we are using middleware for securing our Rest API


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmjgxmrgo72pejwaj65o.png)


note : 

By using either the $fillable or $guarded property, you have control over which attributes can be assigned via mass assignment, providing a level of security and control over your model's data.

```php
 protected $fillable = ['title', 'description'];
```

example of storing multi posts with our rest api : 




```javascript
[
    {
        "title": "t2",
        "description": "details"
    },
    {
        "title": "t3",
        "description": "more details"
    }
]
```



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtnvlpxqjvq6f2zeevk5.png)



```php
Route::post('/auth/register', [AuthController::class, 'createUser']);
Route::post('/auth/login', [AuthController::class, 'loginUser']);
Route::post('/auth/logout', [AuthController::class, 'logoutUser']);
Route::apiResource('posts', PostController::class)->middleware('auth:sanctum');

```


Github Code Source :