Membuat REST API CRUD dengan Laravel serta JWT

Di kesempatan kali kita akan membahas cara membuat REST API Laravel versi 11 dengan sistem CRUD (Create, Read, Update, Delete) disertai autentikasi JWT memakai Laravel Sanctum. dulu saya pernah menulis versi lama pakai Laravel 8 + Passport, tapi sekarang buat API sederhana saya lebih milih Sanctum karena lebih ringan dan jadi rekomendasi resmi. API ini bisa dipakai sebagai backend untuk Android Studio, Vue Js frontend, dan web service lainnya.
Fitur yang akan kita bangun mencakup Login, Logout, Register, Update, dan Delete dengan studi kasus simple user. API sebagai backend bisa mengubah profile seperti update name, email, dan password disertai enkripsi bcrypt.
Install Laravel versi terbaru
di tulisan ini saya pakai Laravel 11.x
composer create-project laravel/laravel rest-api-laravel
Penjelasan :
- membuat project laravel terbaru di PC kita dengan bantuan composer
Install Laravel Sanctum
composer require laravel/sanctum
Penjelasan :
- Sanctum adalah library autentikasi yang dikembangkan Laravel. dengan Sanctum kita mendapatkan token untuk mengakses API, dan setiap request ke endpoint yang dilindungi harus disertai header
Authorization : Bearer {TOKEN}
setelah composer selesai, jalankan migrasi supaya tabel personal_access_tokens ikut dibuat:
php artisan migrate
Menyiapkan Database di Laravel
Jangan lupa setup dulu koneksi database, di sini saya pakai MySQL dengan nama database rest-api-laravel. isi file .env seperti berikut:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rest-api-laravel
DB_USERNAME=root
DB_PASSWORD=
Penjelasan :
DB_CONNECTION: database yang kita gunakan, di sini MySQLDB_HOST: alamat host mysqlDB_PORT: port yang digunakan oleh mysqlDB_DATABASE: nama database mysql yang akan digunakanDB_USERNAME: username untuk mengakses database mysqlDB_PASSWORD: password yang digunakan oleh mysql
setingan .env disesuaikan dengan konfigurasi mysql teman-teman. buat yang kesulitan membuat database di mysql bisa kunjungi tutorial saya di cara membuat database mysql
Menyiapkan Model User dan Middleware
setelah Sanctum terinstall, tambahkan trait HasApiTokens di model User:
<?php
namespace App\Models;
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 HasApiTokens, HasFactory, Notifiable;
}
Penjelasan :
- trait
HasApiTokensdari Sanctum membuat modelUserpunya methodcreateToken()dantokens(), jadi kita bisa menerbitkan dan mencabut token untuk user
lalu di routes/api.php, route yang butuh login dibungkus middleware auth:sanctum:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
Route::post('/register', [UserController::class, 'register']);
Route::post('/login', [UserController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', [UserController::class, 'profile']);
Route::patch('/user', [UserController::class, 'patch']);
Route::put('/user', [UserController::class, 'put']);
Route::delete('/user', [UserController::class, 'delete']);
Route::post('/user/logout', [UserController::class, 'logout']);
});
Penjelasan :
Route::middleware('auth:sanctum')melindungi semua route di dalamnya. request tanpa header token yang valid akan ditolak dengan status 401
Membuat Repository User
di project ini saya pakai pola Repository, jadi akses database dipisah dari controller. buat folder app/Repositories lalu file UserRepository.php:
<?php
namespace App\Repositories;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class UserRepository
{
public function create(array $input)
{
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
]);
}
public function update(array $input, User $user)
{
if (isset($input['password'])) {
$input['password'] = Hash::make($input['password']);
}
$user->update($input);
return $user->fresh();
}
public function delete(User $user)
{
$user->delete();
return $user;
}
}
Penjelasan :
Hash::makeuntuk mengenkripsi password, pengganti fungsibcrypt()yang lama- method
create,update,deleteterpisah biar controller tetap ramping
Membuat Controller User
buat controller UserController.php yang memanggil repository dan menerbitkan token Sanctum:
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class UserController extends Controller
{
protected $repo;
public function __construct(UserRepository $repo)
{
$this->repo = $repo;
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
if ($validator->fails()) {
return response()->json([
'status' => false,
'message' => $validator->messages()->first(),
], 400);
}
$user = $this->repo->create($request->all());
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'status' => true,
'message' => 'Berhasil Membuat User baru',
'user' => $user,
'token' => $token,
], 201);
}
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|email|exists:users,email',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json([
'status' => false,
'message' => $validator->messages()->first(),
], 400);
}
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json([
'status' => false,
'message' => 'Email atau password salah',
], 401);
}
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'status' => true,
'message' => 'Login berhasil',
'user' => $user,
'token' => $token,
], 200);
}
public function profile(Request $request)
{
return response()->json($request->user(), 200);
}
public function put(Request $request)
{
return $this->updateProfile($request, false);
}
public function patch(Request $request)
{
return $this->updateProfile($request, true);
}
protected function updateProfile(Request $request, bool $partial)
{
$rules = [
'name' => ($partial ? 'sometimes|' : '') . 'required|string',
'email' => ($partial ? 'sometimes|' : '') . 'required|email|unique:users,email,' . $request->user()->id,
'password' => 'sometimes|string|min:8',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return response()->json([
'status' => false,
'message' => $validator->messages()->first(),
], 400);
}
$user = $this->repo->update($request->all(), $request->user());
return response()->json([
'status' => true,
'message' => 'Berhasil Update user',
'user' => $user,
], 200);
}
public function delete(Request $request)
{
$this->repo->delete($request->user());
return response()->json([
'status' => true,
'message' => 'Berhasil Delete user',
], 200);
}
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json([
'message' => 'Successfully logged out',
], 200);
}
}
Penjelasan :
$user->createToken('auth_token')->plainTextToken;: menerbitkan token Sanctum,plainTextTokenyang mengambil string token-nyaHash::checkuntuk memverifikasi password saat login$request->user()->currentAccessToken()->delete();: menghapus token yang sedang dipakai, sehingga logout
Mencoba Endpoint dengan cURL atau Postman
jalankan server laravel:
php artisan serve
lalu tes dengan cURL. contoh register:
curl -X POST http://127.0.0.1:8000/api/register \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"name":"Sigit","email":"[email protected]","password":"rahasia123"}'
response-nya akan berisi token. pakai token itu untuk akses route yang dilindungi:
curl -X GET http://127.0.0.1:8000/api/user \
-H "Accept: application/json" \
-H "Authorization: Bearer TOKEN_ANDA"
kalau token valid, response mengembalikan data user. kalau tidak, muncul error 401 Unauthenticated. dulu pas pertama kali coba saya sering ketinggalan header Accept: application/json, hasilnya malah dilempar ke halaman login HTML, bingung sendiri 😄
Pertanyaan yang Sering Diajukan
Laravel Sanctum itu apa?
Sanctum adalah paket autentikasi resmi Laravel untuk API. Dia menerbitkan token personal access token (string acak) yang disimpan di tabel personal_access_tokens, dan cukup ringan karena tidak butuh OAuth server seperti Passport.
Kenapa sekarang pakai Sanctum bukan Passport untuk API?
Untuk API sederhana yang cuma butuh token login, Sanctum adalah rekomendasi resmi Laravel. Passport masih dipakai kalau butuh OAuth penuh seperti login dengan aplikasi pihak ketiga (login via GitHub, Google, dll).
Cara mengirim token Sanctum saat request API?
Tambahkan header Authorization: Bearer <token> di setiap request ke route yang dilindungi middleware auth:sanctum. Token didapat dari hasil login atau register.
Berapa lama token Sanctum berlaku?
Secara default token Sanctum tidak kedaluwarsa. Kalau mau ada masa berlaku, set expiresAt() saat membuat token, atau pakai abilities untuk membatasi akses token tertentu.

