How to Build a Rest API with Laravel: A Beginners Guide
Tags: laravel, restapi, backend, webdev
Published: 2023-01-10 11:41:14

---
title: How to Build a Rest API with Laravel: A Beginners Guide
published: true
date: 2022-11-19 13:01:36 UTC
tags: laravel,restapi,backend,webdev
canonical_url: https://www.iankumu.com/blog/laravel-rest-api/?utm_source=rss&utm_medium=devto&utm_campaign=laravel-rest-api
---

With the rise of mobile and javascript web frameworks such as [React](https://reactjs.org/) and [Vue](https://vuejs.org/), Restful APIs have seen their popularity increase. This is because you can maintain one backend serving multiple front-end clients.

Laravel provides a good environment and ecosystem for building your Rest API.

First-party packages such as [Laravel Passport](https://www.iankumu.com/blog/laravel-passport/) and [Laravel Sanctum](https://www.iankumu.com/blog/laravel-sanctum/) provide **API authentication implementation making authentication easy**.

[Laravel Breeze](https://laravel.com/docs/9.x/starter-kits#laravel-breeze) provides starter templates that can help with reset password features.

[Socialite](https://laravel.com/docs/9.x/socialite) and [Scout](https://laravel.com/docs/9.x/scout) provide [Social Login](https://www.iankumu.com/blog/laravel-socialite/) implementations and [Full-text search](https://www.iankumu.com/blog/laravel-search/) functionalities.

The laravel ecosystem provides solutions to almost all problems you can encounter in your development journey thus **providing maximum productivity** to a developer.

This tutorial will explore **how to create a Laravel Rest API with authentication using Laravel Sanctum**.

## What is a Restful API?

[REST](https://aws.amazon.com/what-is/restful-api/) stands for REpresentational State Transfer and it is a pattern used for communication between applications through HTTP. The protocol is stateless meaning no session is stored between the applications. Each request is therefore processed as if it is a new request even though it is repeated.

A benefit of REST APIs is that they can **easily be cached**. It is easy to [cache a response](https://www.iankumu.com/blog/laravel-cache/) from the Rest API in a service such as Redis or Memcached and thus easy to scale.

For an API to be considered Restful, it has to have the following

- Must be accessible over a URL or endpoint 
- Must use any of the REST Methods 

The common REST Methods are:

**GET** -Fetch resources from an API

**POST** -Create a resource in the API

**PUT/PATCH** -Update a resource in the API

**DELETE** – Delete a resource from an API

- Can have HTTP headers 
- Must return a valid response code in each response. 

## How to build a REST API with Laravel 

### Create a new Application

The first step is to create a new Laravel application.

```bash
laravel new rest 
```

### Set up a Model and Migration

The next step is to create a Model and its corresponding migration file. This acts as a blueprint for our database table. In this tutorial, I will use **Products** as my resource.

```bash
php artisan make:model Products -m 
```

The -m flag will instruct Laravel to create the corresponding migration file of the Products Model.

```php
//App/Models/Products
<?php

namespace App\Models;

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

class Products extends Model
{

    use HasFactory;

}
```

The migration file generated will resemble the one below.

```php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};

```

We can start by **updating the migration file** by adding more columns to our database. I will add the following columns: product **name** , product **price** and product **description**

```php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->double('price');
            $table->longText('description');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};

```

We can then **update the Products model** by registering the **mass-assignable variables**. This helps prevent SQL injection by instructing laravel only to accept data containing the specified keys/variables.

```php
//App/Models/Products
<?php

namespace App\Models;

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

class Products extends Model
{
    use HasFactory;

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

The last step is to **set up the database credentials** in the **.env** file and **create the database**

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-rest
DB_USERNAME=root
DB_PASSWORD=password
```

The final step is to migrate the database.

```bash
php artisan migrate 
```

### Create a Database Seeder and Factory

When developing, I prefer to **use fake data** to ensure that I develop **as fast as possible**. Laravel provides a handy **Factory facade** that can allow us to use [Faker](https://github.com/fzaninotto/Faker) to generate dummy data.

We can run this command to create a Factory

```bash
php artisan make:factory ProductsFactory
```

This will create a file in the **databases/factories** folder

We can update the file as follows

```php
//database/factories/ProductsFactory
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Products>
 */
class ProductsFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'name' => $this->faker->word,
            'price' => $this->faker->numberBetween(1, 99),
            'description' => $this->faker->sentence()
        ];
    }
}

```

Now that our factory is ready, we can call it in the DatabaseSeeder file to seed our database.

```php
//database/seeders/DatabaseSeeder
<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        \App\Models\Products::factory(10)->create();
    }
}

```

We can now seed the database

```bash
php artisan db:seed
```

### Create a Controller

Let’s now create a Controller which will contain all the Business logic for the API.

```bash
php artisan make:controller ProductsController -r
```

The -r flag will generate a Controller that is resourceful. This means it will create a controller with all the required methods for a Restful API.

The main methods we will use are **index** , **show** , **store** , **update** and **destroy**. We **can delete** the **create** and **edit** methods as we will not need them. We can update the Products Controller as shown below

```php
//App/Http/Controllers/ProductsController

<?php

namespace App\Http\Controllers;

use App\Http\Resources\ProductResource;
use App\Models\Products;
use Illuminate\Http\Request;

class ProductsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param Products $product
     * @return \Illuminate\Http\Response
     */
    public function show(Products $product)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @param Products $product
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Products $product)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param Products $product
     * @return \Illuminate\Http\Response
     */
    public function destroy(Products $product)
    {
        //
    }
}

```

These methods can be mapped to the default HTTP verbs (get, post, patch/put and delete).

#### Index(Get all Products)

We can use this method to **return all products** present in the database

```php
use App\Models\Products;
public function index()
{
   return Products::all();
}
```

We can further customise it by paginating it or caching the response from the database.

#### Show(Get a Single Product)

We can use this method to **return a single product** present in the database

We can pass the product id as a parameter and we can then fetch it from the database

> Note: I am using API Resources which I will discuss later in the article.

```php
use App\Http\Resources\ProductResource;
use App\Models\Products;

public function show(Products $product)
{
   return new ProductResource($product);
}
```

#### Store(Create a Product)

We can **create a new product record** in the database using this method. A post method can be made to this method through an endpoint to create the record

```php
use App\Http\Resources\ProductResource;
use App\Models\Products;

public function store(Request $request)
{
        $product_name = $request->input('name');
        $product_price = $request->input('price');
        $product_description = $request->input('description');

        $product = Products::create([
            'name' => $product_name,
            'price' => $product_price,
            'description' => $product_description,
        ]);
        return response()->json([
            'data' => new ProductResource($product)
        ], 201);
}
```

#### Update(Update Product Details)

To **update the product details** , we can update the logic of the update method

```php
use App\Http\Resources\ProductResource;
use App\Models\Products;

public function update(Request $request, Products $product)
{
        $product_name = $request->input('name');
        $product_price = $request->input('price');
        $product_description = $request->input('description');

        $product->update([
            'name' => $product_name,
            'price' => $product_price,
            'description' => $product_description,
        ]);
        return response()->json([
            'data' => new ProductResource($product)
        ], 200);
}
```

#### Destroy(Delete a Product)

At times you might want to **delete products** from the database. We can add the following code to delete products from the database.

```php
use App\Models\Products;

public function destroy(Products $product)
{
   $product->delete();
   return response()->json(null,204);
}
```

### Routes and endpoints

Let’s now create the endpoints that will be accessible over HTTP. We can add the routes in the **routes/api.php** file

```php
//routes/api.php
<?php

use App\Http\Controllers\ProductsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::get('products', [ProductsController::class, 'index'])->name('products.index');
Route::get('products/{product}', [ProductsController::class, 'show'])->name('products.show');
Route::post('products', [ProductsController::class, 'store'])->name('products.store');
Route::put('products/{product}', [ProductsController::class, 'update'])->name('products.update');
Route::delete('products/{product}', [ProductsController::class, 'destroy'])->name('products.destroy');

```

These endpoints are mapped to the methods in the ProductsController we created earlier.

We can now test the index method through a GET request. This will return the following response

```json
[
    {
        "id": 1,
        "name": "quo",
        "price": 15,
        "description": "Ut rerum aut deleniti eveniet ad et ullam perferendis.",
        "created_at": "2022-11-18T15:18:13.000000Z",
        "updated_at": "2022-11-18T15:18:13.000000Z"
    },
    {
        "id": 2,
        "name": "maxime",
        "price": 70,
        "description": "Natus officiis repellat vero ea voluptatem mollitia similique.",
        "created_at": "2022-11-18T15:18:13.000000Z",
        "updated_at": "2022-11-18T15:18:13.000000Z"
    }
]
```

### Formatting the Response

The response above is returned in JSON format. It includes details from the database with the column names as the keys.

**What if you want to format this response**? One thing you **might not** want to expose is the **created\_at** and **updated\_at** data. You might also want to **calculate and return** a predefined **discount** back as a response.

Laravel allows us to customize our responses using [API resources](https://laravel.com/docs/9.x/eloquent-resources).

In this example, I will assume that **all products have a 10% discount**. I will therefore **return the product price and the discounted price** as part of the payload in the response.

```bash
php artisan make:resource ProductResource
```

This will transform a model into an array.

```php
//App/Http/Resources/ProductResource
<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ProductResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'product_name' => $this->name,
            'product_price' => "$" . $this->price,
            'discounted_price' => "$" . ($this->price * 0.9),
            'discount' => "$" . ($this->price * 0.1),
            'product_description' => $this->description,
        ];
    }
}

```

Let’s update our index method in Products Controller to use the Product resource

```php
public function index()
{
   return ProductResource::collection(Products::all());
}
```

This will return the newly formatted response

```json
{
    "data": [
        {
            "id": 1,
            "product_name": "quo",
            "product_price": "$15",
            "discounted_price": "$13.5",
            "discount": "$1.5",
            "product_description": "Ut rerum aut deleniti eveniet ad et ullam perferendis."
        },
{
            "id": 2,
            "product_name": "maxime",
            "product_price": "$70",
            "discounted_price": "$63",
            "discount": "$7",
            "product_description": "Natus officiis repellat vero ea voluptatem mollitia similique."
        }
    ]
}
```

### Response Codes

It is important to always **return a valid response code in each request**. These response codes can be used by a consuming application or client to know what exactly happened on the server side.

Here is a list of the most common response codes

- 200 – **Ok**. This signifies it is a success code and it is the default response code 
- 201- **Created**. This shows that a resource has been created. It is useful for POST requests. 
- 204- **No Content**. This signifies that the action was successful but no content is returned. It is useful for DELETE requests since a deleted resource cannot return any body content 
- 400- **Bad Request**. This signifies that the client passed an invalid request to the server 
- 401- **Unauthorized**. This signifies that the client is not authorized to access the resource. It is typically used in authentication and authorization services. 
- 403- **Forbidden**. This signifies that a user is authenticated but is not allowed to access the resource. 
- 404- **Not Found**. This signifies that a resource is not found 
- 500- **Internal Server Error**. This implies that there is an error at the server level 

Laravel allows us to specify the correct response code using the **response()->json()** helper function. It is important to always return a response code so that the client/frontend can display the correct data and “fail gracefully” in the case of an error.

```php
response()->json(data,status code)
```

### Setting up Authentication with [Laravel Sanctum](https://iankumu.com/blog/laravel-sanctum)

We have discussed the most basic way of creating a CRUD REST API in Laravel. We now want to **add authentication to our API** in order to secure it. There are two ways in which we can implement authentication; either through [Laravel Passport](https://iankumu.com/blog/laravel-passport) or [Laravel Sanctum](https://iankumu.com/blog/laravel-sanctum).

**[Passport](https://iankumu.com/blog/laravel-passport)** provides a way in which **applications authenticate themselves over the internet**. It basically adds **Oauth implementation to your API** which other systems can use to authenticate themselves when interacting with your API. It is useful for **public APIs** where you might want to track API usage and also limit requests for each API key.

**[Sanctum](https://iankumu.com/blog/laravel-sanctum)** on the other hand provides a **stateless integration of the normal authentication service** by **using email and passwords to provide authentication** to a client. It is useful for **private/internal APIs** that **don’t need** all the features provided by an OAuth Server.

In this part, I will use [Laravel Sanctum](https://iankumu.com/blog/laravel-sanctum) to create a simple authentication service for my API. I will use the default email and password to authenticate a user.

To learn more about the two authentication packages, you can read the [Laravel Sanctum](https://iankumu.com/blog/laravel-sanctum) article or the [Laravel Passport](https://iankumu.com/blog/laravel-passport) article.

#### Configuration and Setup

We will first create an authentication scaffold using **Laravel Breeze**

```bash
composer require laravel/breeze --dev
```

We can then install the package

```bash
php artisan breeze:install
php artisan migrate
npm install 
npm run dev
```

This will create **a basic authentication scaffold** and a **forgot and reset password** functionality out of the box.

Let’s now **install Laravel sanctum** and set it up

```bash
composer require laravel/sanctum
```

Next is to **publish Sanctum’s configurations**

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

Finally, we can migrate the database that will store the access tokens

```bash
php artisan migrate
```

The last step is to **allow Sanctum to issue access tokens** which will be used to authenticate users’ requests.

```php
App/Models/User
<?php

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\Sanctum\HasApiTokens; //import the trait

class User extends Authenticatable
{
    use HasApiTokens; //add this trait
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

```

We can now create a new controller that will be responsible for the Authentication

```bash
php artisan make:controller UserAuthenticationController
```

#### Register

We can start by fleshing out the **user registration logic**. We will use the default user table that comes with laravel but feel free to add and remove some columns as you please

```php
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

public function register(Request $request)
{
        $name = $request->input('name');
        $email = strtolower($request->input('email'));
        $password = $request->input('password');

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

        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'message' => 'User Account Created Successfully',
            'access_token' => $token,
            'token_type' => 'Bearer',
        ], 201);
}
```

From the code, we can see that **a user account is created** in the database and **an access token is issued to the user** and is returned back to the user as a response.

#### Login

The next important feature is to **allow users to log in**. We can add the following logic

```php
use Illuminate\Support\Facades\Auth;

public function login(Request $request)
    {
        $email = strtolower($request->input('email'));
        $password = $request->input('password');

        $credentials = [
            'email' => $email,
            'password' => $password
        ];
        if (!Auth::attempt($credentials)) {
            return response()->json([
                'message' => 'Invalid login credentials'
            ], 401);
        }

        $user = User::where('email', $request['email'])->firstOrFail();

        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'access_token' => $token,
            'token_type' => 'Bearer',
        ],200);
    }
```

Similar to the registration, we need to **return the access token as soon** as the user credentials have been validated.

If the credentials are wrong, we need to alert the user that their credentials are wrong. But how?🤔

Since a REST API is **stateless, there is no way of flashing responses in real-time**. We, therefore, need to **return a valid response code and a descriptive message** so that a user knows what happened at the server level.

We can use a simple if else statement but this might make our code less clean. A solution is to use the **default Exception Handler** provided by Laravel.

We can add some logic **to apply to the whole API** and catch any Authentication Exceptions and return back a valid API Response back to the client.

We can update the **App/Exceptions/Handler**. **php** to resemble the one below

```php
App/Exceptions/Handler

<?php

namespace App\Exceptions;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Request;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * A list of exception types with their corresponding custom log levels.
     *
     * @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
     */
    protected $levels = [
        //
    ];

    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<\Throwable>>
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->renderable(function (AuthenticationException $exception, Request $request) {
            if ($request->is('api/*')) {
                if ($exception instanceof AuthenticationException) {
                    return $request->expectsJson() ?:
                        response()->json([
                            'message' => 'Unauthenticated.',
                            'status' => 401,
                            'Description' => 'Missing or Invalid Access Token'
                        ], 401);
                }
            }
        });
    }
}

```

This will come in handy when we discuss **middleware**.

#### Logout 

Of course in each system, **we need a logout functionality** so we will also create its function

```php
public function logout()
{
    auth()->user()->tokens()->delete();

    return response()->json([
        'message' => 'Succesfully Logged out'
    ], 200);
}
```

Note that we are using the delete function to **invalidate an existing access token and delete** it from the database. This makes the access token unusable and we can comfortably say the user is logged out.

The final piece left is to create the endpoints/routes in the **routes/api.php** file.

```php
Route::post('login', [UserAuthenticationController::class, 'login']);
Route::post('register', [UserAuthenticationController::class, 'register']);
Route::post('logout', [UserAuthenticationController::class, 'logout'])->middleware('auth:sanctum');
```

Only the logout endpoint **needs middleware** because it requires a token to be passed to v **erify which user is being logged out** of the system.

### Scopes and Middlewares

[Scopes](https://laravel.com/docs/9.x/sanctum#token-abilities) are commonly used in APIs to **assign abilities to tokens**. They help flesh out **what a user can and cannot do in a system**. Think of them as **permissions you grant to users** once you onboard them. Some users can access financial records in a system while others cannot.

[Middlewares](https://laravel.com/docs/9.x/sanctum#token-ability-middleware) on the other hand are **used to protect endpoints from unauthorized access**. Think of them as **a gate that filters out valid requests from unauthorized and malicious requests**. They help **safeguard your endpoints** from being accessed by users who have no role in accessing them.

We can add the **auth:sanctum** middleware to the product’s endpoints to safeguard them. This means that for a request to be considered valid, it has to have the **Authorization: Bearer token** headers(where the token is the actual access token issued by the API).

```
HEADERS {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer <Token>'
    }
```

Each request **has to include the bearer token** in the headers or the server will respond with a 401(Unauthorized) response.

### Grouping Endpoints

In most cases, you might have **multiple endpoints that share** some common things such as **version** (e.g v1,v2), **prefixes** (admin), or **middleware**.

It is important to **always version your APIs** especially if they are being used by the public. This helps in **preventing breaking changes** and also **allows for backward compatibility** in the event new APIs are available.

We can group these endpoints using the **Route::group** method

```php
Route::group(['middleware' => ['auth:sanctum']], function () {

    //All Routes that share the auth:sanctum middleware
});
```

This way we can have our code organized and clean. In this example, I will group the routes to be of **version 1** and use the **auth:sanctum** middleware.

We might also want to **reduce the size** of the **api.php** file by making each resource use **apiresource.** This simple function reduces the file size by almost 60% and makes reading and maintaining the code an easy task.

```php
Route::apiResource('products', ProductsController::class);
```

The **apiresource method** under the hood works by mapping the main functions(index, show, store, update and delete) in our controller to their various endpoints.

For example **products.show** is mapped to the endpoint **api/products/{product}.**

These are some **cool techniques** you can use to optimize your development experience and become more productive when developing your APIs.

The final **routes/api.php** file should resemble the one below

```php
//routes/api.php
<?php

use App\Http\Controllers\ProductsController;
use App\Http\Controllers\UserAuthenticationController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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!
|
*/

//These routes are NOT protected using middleware

Route::prefix('v1')->group(function () {
    Route::post('login', [UserAuthenticationController::class, 'login']);
    Route::post('register', [UserAuthenticationController::class, 'register']);
});

//These routes are protected using middleware
Route::prefix('v1')->middleware('auth:sanctum')->group(function () {
    Route::post('logout', [UserAuthenticationController::class, 'logout']);
    Route::apiResource('products', ProductsController::class);
});

```

### Testing using Postman

The last step in this tutorial is to test our API through an HTTP Client. There are numerous HTTP Clients such as [Postman](https://www.postman.com/) and [Thunderclient](https://www.thunderclient.com/) just to name a few.

I personally use **Thunderclient** because it integrates seamlessly with Vscode which is my goto editor. It can be added as a Vscode extension thereby making your Vscode editor a powerful editor and REST API client at the same time.

It improves my productivity and development experience immensely. You are free to use any other HTTP Client of your choice.

I will use postman in this article as most people are familiar with it.

We will break down the test from **authentication** to the **basic CRUD**

#### Authentication

We can further break down authentication into registration, login and logout.

##### Registration

We can make a POST request to the endpoint **api/v1/register** with the body on postman

![Laravel REST APIs(register)](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Register-1024x579.jpg)
_Successful Registration_

##### Login

To test login functionality, we can make a POST request to the **api/v1/login**

![Laravel REST APIs(login)](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Failed-Login-1024x541.jpg)
_Failed Login_

A failed login attempt returns a 401(Unauthorized) Status Code and also returns a descriptive message to the client

![Laravel REST APIs(login)](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Successful-Login-1024x576.jpg)
_Successful Login_

A successful login attempt returns a 200(OK) Status Code and also returns an access token that can be stored for future use.

##### Logout

Logout can be tested by making a POST request to the api/v1/logout endpoint. We also need to attach the bearer token assigned to us during registration/login to the Headers.

![Laravel REST APIs(logout)](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Successful-Logout-1024x540.jpg)
_Logout_

Upon success, a descriptive message and a 200(OK) Status Code are returned back to a User.

We can now test the **Product resource**. Similar to log out, we also need to attach the bearer token assigned to us during registration/login to the Headers. This is because all the product’s endpoints are protected by the **auth:sanctum** middleware.

If we try to access any product’s endpoint **without the access token** , the server will respond with a 401(Unauthorized) Status Code.

![Unauthorized Access](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Unauthorized-Access-1024x588.jpg)
_Unauthorized Access_

This is because we registered an Exception Handler to catch any access to the API that is not authorized and return a 401 Status Code with a descriptive response. This protects our API endpoints from unauthorized access.

#### Get All Products

All products can be returned by making a **GET** request to the **api/v1/products** endpoint.

![Get all products REST API](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Get-All-Products-1024x628.jpg)
_Get All Products_

#### Get A Single Product

We can fetch a single product from the API by making a **GET** request to the **api/v1/products/{id}** endpoint

![Get a single product REST API](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Get-a-Single-Product-1024x660.jpg)
_Get a Single Product_

#### Add A Product

We can add a product by making a **POST** request to the **api/v1/products** endpoint

![Add a Product REST API](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Add-a-Product-1024x659.jpg)
_Add a Product_

#### Update A Product

To update a product’s details, we can make a **PUT/PATCH** request to the **api/v1/products/{id}** endpoint.

![Update a Product REST API](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Update-a-Product-Details-1024x657.jpg)
_Update a Product_

#### Delete A Product

We can make a **DELETE** request to the **api/v1/products/{id}** endpoint to delete a product from the database

![Delete a Product REST API](https://www.iankumu.com/blog/wp-content/uploads/2022/11/Delete-a-Product-1024x519.jpg)
_Delete a Product_

## In Closing

In this article, we have covered what Rest APIs are and how to create one in Laravel. We have also covered API authentication and Using Middleware to control access to your API. I hope this article was insightful and helped you create a powerful REST API in laravel.

Thank you for reading.

The post [How to Build a Rest API with Laravel: A Beginners Guide](https://www.iankumu.com/blog/laravel-rest-api/) appeared first on [Ian Kumu's Blog](https://www.iankumu.com/blog).