Tutorial Membuat REST API dengan Laravel yang Mudah dan Praktis
Admin
Penulis Artikel
Tutorial Lengkap Laravel REST API
Best Practice — Studi Kasus Todo List
BACA JUGA: Panduan Lengkap Menginstall SASS di Windows
1. Pendahuluan
Di era modern pengembangan perangkat lunak, arsitektur berbasis API (Application Programming Interface) menjadi standar yang hampir wajib dikuasai oleh setiap developer. Mulai dari aplikasi mobile, Single Page Application (SPA), hingga integrasi antar layanan — semuanya membutuhkan API yang handal, aman, dan mudah di-maintain.
Tutorial ini cocok untuk kamu yang:
Baru mulai belajar Laravel dan ingin langsung belajar membuat REST API
Sudah tahu dasar Laravel MVC tapi ingin memahami struktur API yang baik
Ingin memiliki boilerplate proyek REST API yang siap dikembangkan lebih lanjut
Di tutorial ini kita akan membangun:
Autentikasi menggunakan JWT (JSON Web Token)
Sistem role sederhana:
admindanuserCRUD Todo — admin bisa kelola semua, user hanya miliknya sendiri
Controller di folder
API/, menggunakan API Resource dan Form Request
2. Mengapa Laravel 11?
📖 Referensi: laravel.com/docs/11.x/releases
Laravel 11 dirilis pada Maret 2024 dan membawa banyak perubahan signifikan dari versi sebelumnya. Berikut alasan mengapa tutorial ini menggunakan Laravel 11:
Alasan Teknis
a. Struktur Lebih Ramping (Slim Skeleton)
Laravel 11 memangkas banyak file yang sebelumnya ada di versi 10 ke bawah. File app/Http/Kernel.php dihapus dan digantikan dengan konfigurasi middleware langsung di bootstrap/app.php. Ini membuat proyek lebih bersih dan tidak bloated untuk pemula.
b. Route API Dipisah Sejak Awal
Di Laravel 11, file routes/api.php tidak lagi di-load secara otomatis. Kamu harus menginstallnya dulu dengan php artisan install:api, yang mengajarkan pemula bahwa pemisahan route web dan API adalah praktik yang disengaja.
c. Support PHP 8.2+
Laravel 11 mengharuskan PHP 8.2 ke atas, artinya kamu otomatis menggunakan fitur PHP modern seperti readonly properties, enum, dan fibers.
d. LTS Terkini
Laravel 11 mendapat dukungan bug fix hingga Agustus 2025 dan security fix hingga Agustus 2026, menjadikannya pilihan stabil untuk proyek jangka panjang.
e. Jembatan Migrasi yang Mulus
Laravel dirancang dengan prinsip keberlanjutan. Memulai dengan Laravel 11 adalah langkah strategis karena framework ini berbagi inti mesin yang sama dengan versi terbaru. Perubahan yang ada bersifat evolusioner, bukan revolusioner, sehingga ketika Anda memutuskan untuk melakukan pembaruan ke versi di atasnya, proses transisi dapat dilakukan dengan sangat minim perubahan kode (seamless upgrade path). Ini menjadikan Laravel 11 sebagai titik mulai yang aman sekaligus relevan untuk jangka panjang.
3. Apa itu REST API?
REST (Representational State Transfer) adalah sebuah architectural style untuk membangun layanan web. API yang mengikuti prinsip REST disebut RESTful API. REST bekerja di atas protokol HTTP dan menggunakan URL (endpoint) untuk mengidentifikasi resource, serta HTTP Method untuk mendefinisikan aksi terhadap resource tersebut.
HTTP Methods yang Wajib Kamu Tahu
Method | Kegunaan | Contoh Endpoint | Aksi |
|---|---|---|---|
GET | Mengambil daftar data |
| Ambil semua todo |
GET | Mengambil satu data |
| Ambil todo ID 1 |
POST | Membuat data baru |
| Buat todo baru |
PUT | Update semua field |
| Update seluruh data todo ID 1 |
PATCH | Update sebagian field |
| Update sebagian data todo ID 1 |
DELETE | Menghapus data |
| Hapus todo ID 1 |
HTTP Status Code yang Umum Digunakan
Kode | Nama | Kapan Digunakan |
|---|---|---|
200 | OK | Request berhasil (GET, PUT, PATCH) |
201 | Created | Data berhasil dibuat (POST) |
204 | No Content | Berhasil tapi tidak ada response body (DELETE) |
400 | Bad Request | Request tidak valid |
401 | Unauthorized | Belum login / token tidak valid |
403 | Forbidden | Sudah login tapi tidak punya izin |
404 | Not Found | Data tidak ditemukan |
422 | Unprocessable Entity | Validasi gagal |
500 | Internal Server Error | Error di server |
Contoh Format Response JSON yang Konsisten
Response API yang baik selalu menggunakan format yang konsisten. Berikut format yang akan kita gunakan:
Response Sukses:
{
"success": true,
"message": "Todos retrieved successfully",
"data": [
{
"id": 1,
"title": "Belajar Laravel",
"is_completed": false,
"user": { "id": 1, "name": "Budi" }
}
]
}Response Error:
{
"success": false,
"message": "Validation failed",
"errors": {
"title": ["The title field is required."] }
}4. Mengapa Laravel Cocok untuk REST API?
Laravel memiliki fitur-fitur bawaan yang sangat membantu dalam membangun REST API yang profesional:
Eloquent ORM — Interaksi dengan database menjadi sangat mudah dan ekspresif
API Resource — Mengontrol secara presisi data yang dikembalikan ke client (docs)
Form Request — Memindahkan logika validasi dari controller ke kelas tersendiri
Middleware — Mudah menambahkan lapisan keamanan seperti autentikasi dan otorisasi role
Route Groups & Prefix — Mudah mengelompokkan route API dengan prefix
/api/v1/JWT / Sanctum — Dukungan autentikasi API yang fleksibel
5. Persiapan & Instalasi
📖 Referensi: laravel.com/docs/11.x/installation
Persyaratan Sistem
Kebutuhan | Versi Minimum |
|---|---|
PHP | 8.2 |
Composer | 2.x |
MySQL | 8.0 / MariaDB 10.x |
Node.js | 18.x (opsional, untuk frontend) |
Postman | Versi terbaru |
Instalasi Laravel 11
Buka terminal dan jalankan salah satu perintah berikut:
composer create-project laravel/laravel:^11.0 laravel-todoMasuk ke folder proyek dan jalankan server:
cd laravel-todo php artisan serveBuka browser dan kunjungi http://127.0.0.1:8000. Jika muncul halaman welcome Laravel, instalasi berhasil.
Instalasi Route API
Di Laravel 11, route API tidak otomatis tersedia. Kita perlu menginstallnya:
php artisan install:apiPerintah ini akan membuat file routes/api.php, migration untuk tabel personal_access_tokens, dan mendaftarkan route API secara otomatis.
6. Struktur Proyek
Berikut gambaran struktur folder yang akan kita bangun:
laravel-todo/
├── app/
│ ├── Http/
│ │ ├── Controllers/
│ │ │ └── API/ ← Controller khusus API
│ │ │ ├── AuthController.php
│ │ │ ├── TodoController.php
│ │ │ └── UserController.php
│ │ ├── Middleware/
│ │ │ └── RoleMiddleware.php ← Middleware role
│ │ └── Requests/
│ │ ├── Auth/
│ │ │ ├── LoginRequest.php
│ │ │ └── RegisterRequest.php
│ │ └── Todo/
│ │ ├── StoreTodoRequest.php
│ │ └── UpdateTodoRequest.php
│ ├── Models/
│ │ ├── User.php
│ │ └── Todo.php
│ └── Http/
│ └── Resources/
│ ├── TodoResource.php ← API Resource
│ └── UserResource.php
├── database/
│ ├── migrations/
│ └── seeders/
├── routes/
│ ├── api.php ← Route API
│ └── web.php ← Route Web (untuk MVC nanti)
└── bootstrap/
└── app.php ← Konfigurasi middleware (baru di L11)💡 Mengapa controller diletakkan di folder API/?
Agar controller untuk API terpisah dari controller untuk tampilan web (MVC)
Jika suatu saat menambahkan Blade, tidak perlu mencampur logika API dan Web
Memudahkan maintenance dan pengembangan tim besar
Merupakan best practice yang direkomendasikan industri
Konfigurasi Database
Buat Database
CREATE DATABASE laravel_todo;Konfigurasi .env
Buka file .env di root proyek dan sesuaikan:
APP_NAME="Laravel Todo API"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_todo
DB_USERNAME=root
DB_PASSWORD=
JWT_SECRET= # akan diisi setelah install JWT
JWT_ALGO=HS256
JWT_TTL=60 # token expired dalam 60 menit8. Membuat Migration & Model
📖 Referensi: laravel.com/docs/11.x/eloquent | laravel.com/docs/11.x/migrations
Migration: Tambah Kolom Role ke Tabel Users
php artisan make:migration add_role_to_users_table --table=users<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void {
Schema::table('users', function (Blueprint $table) {
$table->enum('role', ['admin', 'user'])->default('user')->after('email');
});
}
public function down(): void {
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('role');
});
}
};Migration: Tabel Todos
php artisan make:migration create_todos_table<?php
return new class extends Migration {
public function up(): void {
Schema::create('todos', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('description')->nullable();
$table->boolean('is_completed')->default(false);
$table->timestamps();
});
}
public function down(): void {
Schema::dropIfExists('todos');
}
};php artisan migrateModel User (app/Models/User.php)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
protected $fillable = ['name', 'email', 'password', 'role'];
protected $hidden = ['password', 'remember_token'];
protected function casts(): array {
return ['email_verified_at' => 'datetime', 'password' => 'hashed'];
}
// Relasi: satu user punya banyak todo
public function todos() {
return $this->hasMany(Todo::class);
}
// Helper: cek apakah user adalah admin
public function isAdmin(): bool {
return $this->role === 'admin';
}
// Wajib untuk JWT
public function getJWTIdentifier() { return $this->getKey(); }
public function getJWTCustomClaims() { return []; }
}
Model Todo (app/Models/Todo.php)
php artisan make:model Todo<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Todo extends Model
{
protected $fillable = ['user_id', 'title', 'description', 'is_completed'];
protected $casts = ['is_completed' => 'boolean'];
// Relasi: todo dimiliki oleh seorang user
public function user() {
return $this->belongsTo(User::class);
}
}9. Instalasi & Konfigurasi JWT
JWT, atau JSON Web Token, adalah standar terbuka yang digunakan untuk pertukaran data yang aman antara dua pihak. Dalam konteks REST API di Laravel, JWT sangat berguna untuk mengotentikasi pengguna. Dengan menggunakan JWT, server dapat mengeluarkan token kepada pengguna setelah mereka berhasil melakukan login. Token ini kemudian digunakan dalam setiap permintaan berikutnya untuk mengakses sumber daya yang dilindungi.
Package php-open-source-saver/jwt-auth adalah salah satu solusi yang populer dan kompatibel dengan Laravel 11. Package ini memungkinkan pengembang untuk dengan mudah mengimplementasikan otentikasi berbasis token di aplikasi Laravel Dengan menggunakan JWT, pengembang dapat memastikan bahwa hanya pengguna yang telah terautentikasi yang dapat mengakses API, sehingga meningkatkan keamanan aplikasi secara keseluruhan. Selain itu, JWT bersifat stateless, yang berarti server tidak perlu menyimpan informasi sesi, menjadikannya lebih efisien dalam penggunaan sumber daya.
Install Package
composer require php-open-source-saver/jwt-authPublish Config
php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"Generate JWT Secret Key
php artisan jwt:secretPerintah ini akan otomatis mengisi JWT_SECRET di file .env kamu.
Konfigurasi Auth Guard (config/auth.php)
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
/* kode lainnya */
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt', // ← ubah dari 'token' ke 'jwt'
'provider' => 'users',
],
],10. Membuat Seeder & Roles
php artisan make:seeder UserSeeder<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class UserSeeder extends Seeder
{
public function run(): void {
// Buat akun Admin
User::create([
'name' => 'Admin',
'email' => 'admin@example.com',
'password' => Hash::make('password'),
'role' => 'admin',
]);
// Buat akun User biasa
User::create([
'name' => 'User Biasa',
'email' => 'user@example.com',
'password' => Hash::make('password'),
'role' => 'user',
]);
}
}Pada DatabaseSeeder.php
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
$this->call([
UserSeeder::class,
// Tambahkan seeder lain di sini jika ada
]);
}
}
Setelah didaftarkan di DatabaseSeeder.php lalu jalankan:
php artisan db:seed11. Membuat API Resource
📖 Referensi: laravel.com/docs/11.x/eloquent-resources
API Resource memungkinkan kita mengontrol secara presisi bentuk data JSON yang dikirim ke client. Ini adalah best practice agar model database tidak langsung "bocor" ke respons API.
⚠️ Mengapa harus pakai API Resource?
Model
Usermenyimpan kolompassword. Tanpa Resource,return User::all()akan mengirim data sensitif ke client!Kamu mengontrol sepenuhnya field apa yang tampil di response
Bisa menambahkan computed fields yang tidak ada di tabel database
TodoResource
php artisan make:resource TodoResource<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class TodoResource extends JsonResource
{
public function toArray(Request $request): array {
return [
'id' => $this->id,
'title' => $this->title,
'description' => $this->description,
'is_completed' => $this->is_completed,
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at->toDateTimeString(),
// Hanya tampil jika relasi user di-load dengan ->load('user')
'user' => new UserResource($this->whenLoaded('user')),
];
}
}UserResource
php artisan make:resource UserResource<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array {
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'role' => $this->role,
// TIDAK menampilkan password!
];
}
}12. Membuat Form Request
📖 Referensi: laravel.com/docs/11.x/validation#form-request-validation
Form Request adalah kelas khusus untuk validasi dan otorisasi sebelum data masuk ke controller. Controller menjadi lebih bersih (Single Responsibility Principle).
RegisterRequest
php artisan make:request Auth/RegisterRequest<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class RegisterRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array {
return [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
];
}
public function messages(): array {
return [
'name.required' => 'Nama wajib diisi.',
'email.required' => 'Email wajib diisi.',
'email.unique' => 'Email sudah terdaftar.',
'password.confirmed' => 'Konfirmasi password tidak cocok.',
];
}
// Override agar error validasi dikembalikan sebagai JSON
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json([
'success' => false,
'message' => 'Validation failed',
'errors' => $validator->errors(),
], 422));
}
}LoginRequest
php artisan make:request Auth/LoginRequest<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class LoginRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array {
return [
'email' => 'required|string|email',
'password' => 'required|string',
];
}
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json([
'success' => false, 'message' => 'Validation failed',
'errors' => $validator->errors(),
], 422));
}
}
StoreTodoRequest
php artisan make:request Todo/StoreTodoRequest<?php
namespace App\Http\Requests\Todo;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class StoreTodoRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array {
return [
'title' => 'required|string|max:255',
'description' => 'nullable|string',
'is_completed' => 'boolean',
];
}
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json([
'success' => false, 'message' => 'Validation failed',
'errors' => $validator->errors(),
], 422));
}
}UpdateTodoRequest
php artisan make:request Todo/UpdateTodoRequest<?php
namespace App\Http\Requests\Todo;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class UpdateTodoRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array {
return [
'title' => 'sometimes|required|string|max:255',
'description' => 'nullable|string',
'is_completed' => 'boolean',
];
}
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json([
'success' => false, 'message' => 'Validation failed',
'errors' => $validator->errors(),
], 422));
}
}
13. Membuat Controller di Folder API
AuthController
php artisan make:controller API/AuthController<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\{LoginRequest, RegisterRequest};
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
/** POST /api/auth/register */
public function register(RegisterRequest $request): JsonResponse {
$user = User::create([...$request->validated(), 'role' => 'user']);
$token = Auth::login($user);
return response()->json([
'success' => true,
'message' => 'User registered successfully',
'data' => ['user' => new UserResource($user), 'token' => $token, 'type' => 'bearer'],
], 201);
}
/** POST /api/auth/login */
public function login(LoginRequest $request): JsonResponse {
if (!$token = Auth::attempt($request->only('email', 'password'))) {
return response()->json(['success' => false, 'message' => 'Email atau password salah'], 401);
}
return response()->json([
'success' => true,
'message' => 'Login successful',
'data' => [
'user' => new UserResource(Auth::user()),
'token' => $token,
'type' => 'bearer',
'expires_in' => config('jwt.ttl') * 60,
],
]);
}
/** POST /api/auth/logout */
public function logout(): JsonResponse {
Auth::logout();
return response()->json(['success' => true, 'message' => 'Successfully logged out']);
}
/** POST /api/auth/refresh */
public function refresh(): JsonResponse {
return response()->json([
'success' => true,
'data' => ['user' => new UserResource(Auth::user()), 'token' => Auth::refresh()],
]);
}
/** GET /api/auth/me */
public function me(): JsonResponse {
return response()->json(['success' => true, 'data' => new UserResource(Auth::user())]);
}
}TodoController
php artisan make:controller API/TodoController<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Requests\Todo\{StoreTodoRequest, UpdateTodoRequest};
use App\Http\Resources\TodoResource;
use App\Models\Todo;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
class TodoController extends Controller
{
/** GET /api/todos
* - Admin : lihat semua todo
* - User : hanya lihat miliknya sendiri
*/
public function index(): JsonResponse {
$user = Auth::user();
$todos = $user->isAdmin()
? Todo::with('user')->latest()->paginate(10)
: Todo::where('user_id', $user->id)->latest()->paginate(10);
return response()->json([
'success' => true,
'message' => 'Todos retrieved successfully',
'data' => TodoResource::collection($todos),
'meta' => [
'current_page' => $todos->currentPage(),
'last_page' => $todos->lastPage(),
'per_page' => $todos->perPage(),
'total' => $todos->total(),
],
]);
}
/** POST /api/todos */
public function store(StoreTodoRequest $request): JsonResponse {
$todo = Todo::create(['user_id' => Auth::id(), ...$request->validated()]);
return response()->json([
'success' => true,
'message' => 'Todo created successfully',
'data' => new TodoResource($todo),
], 201);
}
/** GET /api/todos/{id} */
public function show(Todo $todo): JsonResponse {
if (!Auth::user()->isAdmin() && $todo->user_id !== Auth::id()) {
return response()->json(['success' => false, 'message' => 'Unauthorized.'], 403);
}
return response()->json(['success' => true, 'data' => new TodoResource($todo->load('user'))]);
}
/** PUT/PATCH /api/todos/{id} */
public function update(UpdateTodoRequest $request, Todo $todo): JsonResponse {
if (!Auth::user()->isAdmin() && $todo->user_id !== Auth::id()) {
return response()->json(['success' => false, 'message' => 'Unauthorized.'], 403);
}
$todo->update($request->validated());
return response()->json(['success' => true, 'message' => 'Todo updated successfully', 'data' => new TodoResource($todo)]);
}
/** DELETE /api/todos/{id} */
public function destroy(Todo $todo): JsonResponse {
if (!Auth::user()->isAdmin() && $todo->user_id !== Auth::id()) {
return response()->json(['success' => false, 'message' => 'Unauthorized.'], 403);
}
$todo->delete();
return response()->json(['success' => true, 'message' => 'Todo deleted successfully']);
}
}UserController (Khusus Admin)
php artisan make:controller API/UserController<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\JsonResponse;
class UserController extends Controller
{
/** GET /api/users — daftar semua user (khusus admin) */
public function index(): JsonResponse {
$users = User::withCount('todos')->paginate(10);
return response()->json(['success' => true, 'data' => UserResource::collection($users)]);
}
/** GET /api/users/{id} — detail user (khusus admin) */
public function show(User $user): JsonResponse {
return response()->json(['success' => true, 'data' => new UserResource($user->load('todos'))]);
}
}14. Mendefinisikan Routes API
📖 Referensi: laravel.com/docs/11.x/routing
Buka routes/api.php dan definisikan semua route:
<?php
use App\Http\Controllers\API\{AuthController, TodoController, UserController};
use Illuminate\Support\Facades\Route;
// ─── Public Routes (Tidak Perlu Token) ───────────────────────────────────
Route::prefix('auth')->group(function () {
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
});
// ─── Protected Routes (Butuh JWT Token) ──────────────────────────────────
Route::middleware('auth:api')->group(function () {
// Auth Routes
Route::prefix('auth')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::post('/refresh', [AuthController::class, 'refresh']);
Route::get('/me', [AuthController::class, 'me']);
});
// Todo Routes (semua user, logika admin/user di controller)
Route::apiResource('todos', TodoController::class);
// User Routes (khusus admin)
Route::middleware('role:admin')->group(function () {
Route::apiResource('users', UserController::class)->only(['index', 'show']);
});
});Route yang Dihasilkan oleh apiResource
Method | URI | Action | Route Name |
|---|---|---|---|
GET |
| index | todos.index |
POST |
| store | todos.store |
GET |
| show | todos.show |
PUT/PATCH |
| update | todos.update |
DELETE |
| destroy | todos.destroy |
Cek semua route yang terdaftar:
php artisan route:list --path=api15. Middleware Role
📖 Referensi: laravel.com/docs/11.x/middleware
Buat RoleMiddleware
php artisan make:middleware RoleMiddleware<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string ...$roles) {
$user = Auth::user();
if (!$user) {
return response()->json(['success' => false, 'message' => 'Unauthenticated.'], 401);
}
if (!in_array($user->role, $roles)) {
return response()->json([
'success' => false,
'message' => 'Forbidden. You do not have the required role.',
'required_roles' => $roles,
'your_role' => $user->role,
], 403);
}
return $next($request);
}
}Daftarkan di bootstrap/app.php
Di Laravel 11, middleware didaftarkan di bootstrap/app.php — bukan di Kernel.php seperti versi lama:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// Daftarkan alias untuk middleware role
$middleware->alias([
'role' => \App\Http\Middleware\RoleMiddleware::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
// Biarkan kosong jika tidak ada kustomisasi
})
->create();16. Testing di Postman
Pastikan server Laravel berjalan: php artisan serve
Kemudian buka Postman dan ikuti langkah-langkah berikut.
Setup Environment di Postman
Variable | Value | Keterangan |
|---|---|---|
|
| Base URL API |
| (kosong dulu) | Akan diisi otomatis setelah login |
📸 Screenshot: Postman — Setup Environment
1. Register User Baru
Field | Value |
|---|---|
Method | POST |
URL |
|
Header |
|
Body (raw JSON):
{
"name": "Ainun",
"email": "ainun@example.com",
"password": "password123",
"password_confirmation": "password123"
}Response yang diharapkan (201 Created):
{
"success": true,
"message": "User registered successfully",
"data": {
"user": { "id": 3, "name": "Ainun", "email": "ainun@example.com", "role": "user" },
"token": "eyJ0eXAiOiJKV1Qi...",
"type": "bearer"
}
}📸 Screenshot: Postman — Register Request & Response 201 Created
2. Login
{
"email": "admin@example.com",
"password": "password"
}Tips: Tambahkan Script di tab Scripts Postman untuk menyimpan token otomatis:
// Tab "Scripts" di Postman
var response = pm.response.json();
if (response.data && response.data.token) {
pm.environment.set("token", response.data.token);
console.log("Token saved:", response.data.token);
}📸 Screenshot: Postman — Login dengan auto-save token di tab Tests
3. Menggunakan Token (Authorization)
Untuk semua request yang membutuhkan autentikasi, tambahkan header:
Authorization: Bearer {{token}}Atau gunakan tab Authorization → Type: Bearer Token → Value: {{token}}
📸 Screenshot: Postman — Tab Authorization dengan Bearer Token aktif
4. Buat Todo Baru
Method: POST URL: {{base_url}}/todos (sertakan Bearer Token)
{
"title": "Belajar Laravel 11",
"description": "Pelajari fitur baru Laravel 11 termasuk struktur slim skeleton",
"is_completed": false
}📸 Screenshot: Postman — Create Todo POST Request & Response 201
5. Ambil Semua Todo
Method: GET URL: {{base_url}}/todos (sertakan Bearer Token)
6. Update Todo
Method: PUT URL: {{base_url}}/todos/1
{
"title": "Belajar Laravel 11 - Updated",
"is_completed": true
}📸 Screenshot: Postman — Update Todo POST Request & Response 200
7. Hapus Todo
Method: DELETE URL: {{base_url}}/todos/1
8. Test Role — Akses Daftar User (Khusus Admin)
Login sebagai user lalu akses GET {{base_url}}/users. Jika menggunakan token user biasa, response akan:
{
"success": false,
"message": "Forbidden. You do not have the required role.",
"required_roles": ["admin"],
"your_role": "user"
}📸 Screenshot: Postman — Test Role Forbidden 403 Response
Rangkuman Semua Endpoint
Method | Endpoint | Auth | Role | Keterangan |
|---|---|---|---|---|
POST |
| Tidak | - | Daftar akun baru |
POST |
| Tidak | - | Login |
POST |
| Ya | - | Logout |
POST |
| Ya | - | Refresh token |
GET |
| Ya | - | Data user login |
GET |
| Ya | admin/user | Lihat todo |
POST |
| Ya | admin/user | Buat todo |
GET |
| Ya | admin/user | Detail todo |
PUT/PATCH |
| Ya | admin/user | Update todo |
DELETE |
| Ya | admin/user | Hapus todo |
GET |
| Ya | admin | Daftar semua user |
GET |
| Ya | admin | Detail user |
17. Persiapan untuk Fitur MVC di Masa Depan
Salah satu keuntungan besar dari struktur yang sudah kita bangun adalah kemudahannya untuk dikembangkan dengan tampilan web berbasis Blade (MVC) di masa depan.
Yang TIDAK Perlu Diubah
Model (
app/Models/) — digunakan bersama API dan WebMigration & Database — sama persis
Seeder — sama persis
Logika bisnis ([opsional] bisa di-refactor ke Service layer)
Yang Perlu Ditambahkan Nanti
1. Web Controller (terpisah dari API Controller)
php artisan make:controller Web/TodoController2. Route Web di routes/web.php
Route::middleware(['auth'])->group(function () {
Route::resource('todos', \App\Http\Controllers\Web\TodoController::class);
});3. Instalasi Laravel Breeze untuk tampilan web
composer require laravel/breeze --dev php artisan breeze:install blade
Tips: Service Layer untuk Kode yang Lebih Bersih
Agar tidak ada duplikasi logika antara API dan Web Controller, pertimbangkan membuat Service Layer:
// app/Services/TodoService.php
class TodoService
{
public function getAllTodosForUser(User $user) {
return $user->isAdmin()
? Todo::with('user')->latest()->paginate(10)
: Todo::where('user_id', $user->id)->latest()->paginate(10);
}
public function createTodo(array $data): Todo {
return Todo::create($data);
}
}
// Baik API/TodoController maupun Web/TodoController
// sama-sama memanggil TodoService — tidak ada duplikasi logika!✅ Gambaran Arsitektur dengan Service Layer:
API/TodoController → memanggil
TodoService→ return JSONWeb/TodoController → memanggil
TodoService→ return Blade ViewTodoService→ berinteraksi dengan ModelTodoLogika bisnis hanya ada di satu tempat — mudah di-maintain!
18. Kesimpulan & Referensi
Apa yang Telah Kita Bangun?
✅ Instalasi Laravel 11 yang benar dengan struktur slim skeleton
✅ Autentikasi JWT yang aman menggunakan
php-open-source-saver/jwt-auth✅ Sistem Role (admin & user) dengan Middleware custom
✅ API Resource untuk mengontrol format respons JSON
✅ Form Request untuk validasi yang terpisah dari controller
✅ Controller terstruktur di folder
API/yang siap untuk pengembangan MVC✅ Testing lengkap di Postman dengan auto-save token
Langkah Selanjutnya
Menambahkan fitur kategori todo (relasi many-to-many)
Menambahkan filter, sorting, dan search di endpoint
GET /todosMembuat unit test dengan PHPUnit atau Pest
Deploy ke production menggunakan Nginx + PHP-FPM
Menambahkan rate limiting untuk keamanan API
Referensi Resmi Laravel 11
Laravel 11 Documentation — laravel.com/docs/11.x
Laravel Installation — laravel.com/docs/11.x/installation
Laravel 11 Release Notes — laravel.com/docs/11.x/releases
Routing — laravel.com/docs/11.x/routing
Eloquent ORM — laravel.com/docs/11.x/eloquent
Eloquent: API Resources — laravel.com/docs/11.x/eloquent-resources
Form Request Validation — laravel.com/docs/11.x/validation
Middleware — laravel.com/docs/11.x/middleware
JWT Auth Package — github.com/PHP-Open-Source-Saver/jwt-auth
Tutorial Laravel 11 REST API Best Practice — Studi Kasus Todo List dengan JWT & Role
Referensi resmi: laravel.com/docs/11.x
Artikel Terkait
Best Practices Pengembangan Proyek Python dengan .env dan Dotenv
Pelajari cara mengelola konfigurasi proyek Python Anda dengan .env dan dotenv untuk pengembangan yang lebih efisien.
Tips dan Trik Menggunakan SASS untuk Desain Web yang Lebih Baik
Temukan tips dan trik penggunaan SASS untuk meningkatkan efisiensi desain web Anda dengan mudah.
Panduan Membuat Animasi Animated on Scroll di Website Anda
Pelajari cara membuat animasi menarik pada scroll di website Anda dengan tutorial ini. Tampilkan konten dengan cara yang lebih interaktif!
