STEP 1 : Installing PHP and the Laravel Installer
Install php in Mac :
/bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)"
install the Laravel installer via Composer:
composer global require laravel/installer
STEP 2 : Creating an Application
Input :
laravel new thought-manager
thought-manager is my test project name.
you will be asked :
_ _
| | | |
| | __ _ _ __ __ ___ _____| |
| | / _` | __/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|
Which starter kit would you like to install? [None]:
[none ] None
[react ] React
[vue ] Vue
[livewire] Livewire
I choice none because I created a api project.
Then you will be asked :
Which database will your application use? [SQLite]:
[sqlite ] SQLite
[mysql ] MySQL
[mariadb] MariaDB
[pgsql ] PostgreSQL (Missing PDO extension)
[sqlsrv ] SQL Server (Missing PDO extension)
I choice default(SQLite) for test.
Then you will be asked :
Would you like to run npm install and npm run build? (yes/no) [yes]:
At the end, you will see :
INFO Application ready in [thought-manager]. You can start your local development using:
➜ cd thought-manager
➜ composer run dev
New to Laravel? Check out our documentation. Build something amazing!
then :
cd thought-manager
code . // I use vscode
➜ php artisan serve
STEP 3 : Hello API
update routes/web.php :
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TestController;
Route::get('/', function () {
return response()->json([
'success' => true,
'message' => 'Hello, I am thought manager.'
]);
});
Route::prefix('api')->group(function () {
Route::get('/test', [TestController::class, 'index']);
});
but this will have some problem about CSRF, so we need update.
open bootstrap/app.php :
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php', // add this line
)
->withMiddleware(function() {
//
})
->withExceptions(function() {
//
})
->create();
and create a new file in routes/api.php :
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\TestController;
Route::prefix('v1')->group(function () {
Route::get('/test', [TestController::class, 'index']);
});
STEP 4 : remove no need file
#!/bin/bash
echo "Cleaning Laravel frontend resources for API-only project..."
rm -rf resources
rm -rf public/build
rm -rf node_modules
rm -f vite.config.js
rm -f tailwind.config.js
rm -f postcss.config.js
rm -f package.json
rm -f package-lock.json
echo "✅ Cleanup complete. Your Laravel API project is now lean and clean!"
STEP 5 : Init DB
The local SQLite database was created and the initial migrations were completed automatically during Laravel’s initialization. My only task now is to add a test user.
- Add a password line in database/seeders/DatabaseSeeder.php:
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@gmail.com',
'password' => Hash::make('password'), // default not contain this line
]);
}
}
- Run the database seeding command:
php artisan db:seed
STEP 6 : Config JWT(tymon/jwt-auth)
install tymon/jwt-auth :
composer require tymon/jwt-auth
publish config file :
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
It will create config/jwt.php file.
then generatejwt secret :
php artisan jwt:secret
It will create JWT_SECRET in .env file.
Then open config/auth.php, change :
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
STEP 7 : Support Login
create controller :
php artisan make:controller AuthController
and add login method :
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthController extends Controller
{
public function login(Request $request)
{
$credentials = $request->only(['email', 'password']);
try {
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json([
'success' => false,
'message' => 'Invalid email or password',
'data' => null,
], 401);
}
} catch (JWTException $e) {
return response()->json([
'success' => false,
'message' => 'Could not create token',
'data' => null,
], 500);
}
return response()->json([
'success' => true,
'message' => 'Login successful',
'data' => [
'token' => $token,
'token_type' => 'bearer',
'expires_in' => config('jwt.ttl') * 60,
],
]);
}
}
and update routes/api.php :
use App\Http\Controllers\AuthController;
Route::post('/auth/login', [AuthController::class, 'login']);
then update app/Models/User.php :
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
// ...
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
}
When finish use postman or curl test, this is postman body(raw) json :
{
"email": "test@gmail.com",
"password": "password"
}
STEP 8 : API protect
The key code is routes/app.php from :
Route::prefix('v1')->group(function () {
Route::get('/test', [TestController::class, 'index']);
});
to :
Route::prefix('v1')->middleware('auth:api')->group(function () {
Route::get('/test', [TestController::class, 'index']);
});