DEV Community

Cover image for Laravel 11 - Building API using Sanctum
Akram Ghaleb
Akram Ghaleb

Posted on

Laravel 11 - Building API using Sanctum

Table of Contents

Step 1: Install Laravel 11

Open your terminal and Install new Laravel application

composer create-project laravel/laravel sanctum-api
Enter fullscreen mode Exit fullscreen mode

Switch to the project folder

cd sanctum-api
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Sanctum API

Run the following command to install Sanctum with API

php artisan install:api
Enter fullscreen mode Exit fullscreen mode

Step 3: Sanctum Configuration

In app/Models/User.php, we added the HasApiTokens class of Sanctum

<?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;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens;

    /**
     * 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',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Add Blog Migration and Model

Run the following command to add Blog migration and model

php artisan make:model Blog -m
Enter fullscreen mode Exit fullscreen mode

After that go to database/migrations and you will find the created migration file

<?php

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

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

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('blogs');
    }
};
Enter fullscreen mode Exit fullscreen mode

Then go to app/Models/Blog.php

<?php

namespace App\Models;

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

class Blog extends Model
{
    use HasFactory;

    protected $fillable = [
        'title', 'detail'
    ];
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Create Eloquent API Resources

Run the following commands to create Blog API Resources

php artisan make:resource BlogResource
Enter fullscreen mode Exit fullscreen mode

Then go to app/Http/Resources/BlogResource.php

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class BlogResource extends JsonResource
{
    // Transform the resource into an array.
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'detail' => $this->detail,
            'created_at' => $this->created_at->format('d/m/Y'),
            'updated_at' => $this->updated_at->format('d/m/Y'),
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Create Controller Files

Run the following commands to add BaseController & RegisterController & BlogController

php artisan make:controller API/BaseController
php artisan make:controller API/RegisterController
php artisan make:controller API/BlogController
Enter fullscreen mode Exit fullscreen mode

Then go to app/Http/Controllers/API/BaseController.php and add this code

<?php

namespace App\Http\Controllers\API;

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

class BaseController extends Controller
{
    // success response method
    public function sendResponse($result, $message)
    {
        $response = [
            'success' => true,
            'data'    => $result,
            'message' => $message,
        ];

        return response()->json($response, 200);
    }

    // return error response
    public function sendError($error, $errorMessages = [], $code = 404)
    {
        $response = [
            'success' => false,
            'message' => $error,
        ];

        if(!empty($errorMessages)){
            $response['data'] = $errorMessages;
        }

        return response()->json($response, $code);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now go to app/Http/Controllers/API/BaseController.php

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;

class RegisterController extends BaseController
{
    // Register api
    public function register(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ]);

        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());
        }

        $input = $request->all();
        $input['password'] = bcrypt($input['password']);
        $user = User::create($input);
        $success['token'] =  $user->createToken('MyApp')->plainTextToken;
        $success['name'] =  $user->name;

        return $this->sendResponse($success, 'User register successfully.');
    }

    // Login api
    public function login(Request $request): JsonResponse
    {
        if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
            $user = Auth::user();
            $success['token'] =  $user->createToken('MyApp')->plainTextToken;
            $success['name'] =  $user->name;

            return $this->sendResponse($success, 'User login successfully.');
        }
        else{
            return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Finally, go to app/Http/Controllers/API/BlogController.php

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController;
use App\Models\Blog;
use App\Http\Resources\BlogResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;

class BlogController extends BaseController
{
    // Display a listing of the resource.
    public function index(): JsonResponse
    {
        $blogs = Blog::all();

        return $this->sendResponse(BlogResource::collection($blogs), 'Blogs retrieved successfully.');
    }

    // Store a newly created resource in storage.
    public function store(Request $request): JsonResponse
    {
        $input = $request->all();

        $validator = Validator::make($input, [
            'title' => 'required',
            'detail' => 'required'
        ]);

        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());
        }

        $blog = Blog::create($input);

        return $this->sendResponse(new BlogResource($blog), 'Blog created successfully.');
    }

    // Display the specified resource.
    public function show($id): JsonResponse
    {
        $blog = Blog::find($id);

        if (is_null($blog)) {
            return $this->sendError('Blog not found.');
        }

        return $this->sendResponse(new BlogResource($blog), 'Blog retrieved successfully.');
    }

    // Update the specified resource in storage.
    public function update(Request $request, Blog $blog): JsonResponse
    {
        $input = $request->all();

        $validator = Validator::make($input, [
            'title' => 'required',
            'detail' => 'required'
        ]);

        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());
        }

        $blog->title = $input['title'];
        $blog->detail = $input['detail'];
        $blog->save();

        return $this->sendResponse(new BlogResource($blog), 'Blog updated successfully.');
    }

    // Remove the specified resource from storage.
    public function destroy(Blog $blog): JsonResponse
    {
        $blog->delete();

        return $this->sendResponse([], 'Blog deleted successfully.');
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Create API Routes

In this step we will create API routes for login, register, and blogs.

Go to routes/api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\RegisterController;
use App\Http\Controllers\API\BlogController;

Route::controller(RegisterController::class)->group(function(){
    Route::post('register', 'register')->name('register');
    Route::post('login', 'login')->name('login');
});

Route::middleware('auth:sanctum')->group( function () {
    Route::apiResource('blogs', BlogController::class);
    Route::get('user', function (Request $request) {
        return $request->user();
    })->name('user');
});
Enter fullscreen mode Exit fullscreen mode

Step 8: Run Laravel App

Run the database migrations (Set the database connection in .env before migrating)

php artisan serve
Enter fullscreen mode Exit fullscreen mode

Start the local development server

php artisan serve
Enter fullscreen mode Exit fullscreen mode

Step 9: Check following API

Now, go to your Postman to check api

Make sure in the details API, we will use the following headers as listed below

'headers' => [
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '.$accessToken,
]
Enter fullscreen mode Exit fullscreen mode

Now you can simply run the above listed URLs as shown in the screenshot below:

Postman
Postman
Postman
Postman
Postman
Postman
Postman
Postman
Postman

Note: You can download postman file from here

Github Repo

Thanks,

If you enjoy my work, consider buying me a coffee to keep the creativity flowing!

Buy Me A Coffee

Top comments (1)

Collapse
 
ravi_kumar_c0eecdd4955ed6 profile image
Ravi Kumar

Great tutorial, but there is one problem if we hit authenticated api without token this code redirect login route there is error we want to return you are not authenticated please login like this not 500 error
these urls without token

Route::middleware('auth:sanctum')->group( function () {
Route::apiResource('blogs', BlogController::class);
Route::get('user', function (Request $request) {
return $request->user();
})->name('user');
});

Image description