Pendahuluan — merakit perpustakaan mini
Artikel ini adalah #62 (ini) di Seri 4: Pemrograman Web Lanjut v2 — Capstone jalur Laravel. Langkah 7/8: menggabungkan yang sudah kamu punya jadi satu alur nyata.
Domain tetap perpustakaan mini. Hari ini tamu boleh membaca katalog, staf login dapat kartu, lalu staf menambah buku dengan kartu itu. Belum ubah & hapus — itu langkah terakhir jalur.
Awam: Capstone = hari “rakit”. Bukan tool baru besar — kamu menyambungkan pintu baca, loket login, dan pintu tambah buku yang sudah dipelajari terpisah.
Prasyarat: sudah selesai Auth API Dasar: Login & Kartu Anggota (#61) (login +
/api/sayaber-kartu), Controller, Service & Eloquent Laravel (#60) (daftar buku lewat loket), dan Request & Form Request: Menjaga Input API (#59) (satpam slip). Fondasi Instal PHP, Composer & Proyek Laravel (#56) / Struktur Folder,.env& Artisan Laravel (#57). Pakai Laravel 13+ — butuh PHP 8.3+.
Spesifikasi fitur — apa yang “selesai” hari ini?
Bayangkan kamu menjelaskan ke teman dalam tiga kalimat:
- Baca katalog —
GET /api/bukutanpa kartu (tamu boleh lihat rak). - Login staf —
POST /api/login-> dapat stringtoken(kartu anggota digital). - Tambah buku —
POST /api/bukuhanya dengan header Bearer + slip judul/penulis yang valid.
Awam: tanpa kartu -> tambah ditolak. Dengan kartu + slip bagus -> buku baru muncul di daftar.
Istilah — ringkas Capstone
| Istilah | Arti awam | Catatan |
|---|---|---|
| Capstone | Proyek penutup yang merakit potongan sebelumnya | Bukan instal framework baru |
| Bearer | Cara membawa kartu di header HTTP | Authorization: Bearer … |
| Publik vs terlindungi | Pintu boleh tanpa kartu vs wajib kartu | GET daftar = publik; POST tambah = terlindungi |
| Slip valid | Judul/penulis lolos satpam Form Request | Dari Request & Form Request: Menjaga Input API (#59) |
Persiapan — alat yang kamu buka
Alat yang dipakai di artikel ini (fondasi Instal PHP, Composer & Proyek Laravel (#56) / Struktur Folder, .env & Artisan Laravel (#57) — tidak ada unduhan Composer baru hari ini jika Sanctum sudah dari Auth API Dasar: Login & Kartu Anggota (#61)):
- Explorer — pastikan folder
perpustakaan-apiada; cek file Controller / Form Request /routes/web.php. - Terminal — Laragon: menu Terminal · XAMPP: tombol Shell. Jangan asal CMD/PowerShell dari Start Menu (PATH PHP bisa hilang).
- Terminal kedua — wajib: terminal pertama =
php artisan serve. Terminal kedua = ujicurl.exe/ PowerShell (login + tambah + baca). - Editor teks — Notepad / VS Code — sambungkan route POST tambah + method
store. Tip:notepad app\Http\Controllers\BukuController.phpdari terminal kedua (ganti nama file sesuai yang mau dibuka). - Browser — opsional: cek lampu toko. Uji Capstone (POST login/tambah) bukan lewat bilah alamat browser.
Cara buka terminal kedua (baru pertama kali buka dua terminal sekaligus? ini caranya, jangan tutup yang pertama): Laragon — klik menu Terminal sekali lagi di jendela utama Laragon, sebuah jendela terminal baru akan muncul terpisah dari yang pertama. XAMPP — di XAMPP Control Panel, klik tombol Shell sekali lagi, jendela Shell kedua akan terbuka. Kedua jendela boleh hidup bersamaan — jendela pertama tetap menjalankan php artisan serve, jendela kedua kamu pakai untuk mengetik perintah lain.
Buka terminal Laragon/Shell XAMPP (terminal pertama), masuk folder proyek:
cd C:\laragon\www\perpustakaan-api
Di XAMPP biasanya: cd C:\xampp\htdocs\perpustakaan-api. Sesuaikan path jika foldermu beda.
Nyalakan lampu toko di terminal pertama:
php artisan serve
Biarkan jendela itu hidup. Buka terminal kedua (caranya sudah dijelaskan di atas), cd ke folder proyek yang sama — di sini kamu menguji Capstone.
Awam: Terminal 1 = lampu toko. Terminal 2 = tangan menguji tiga pintu. Editor = menyambungkan route. Browser = boleh dicek sebentar, bukan alat utama POST.
Install-dari-nol: jika Sanctum / login belum ada, selesaikan dulu Auth API Dasar: Login & Kartu Anggota (#61) (termasuk composer require laravel/sanctum). Jika PHP/Composer belum dikenal, kembali ke Instal PHP, Composer & Proyek Laravel (#56).
Cek cepat — potongan yang harus sudah ada
Sebelum merakit, pastikan di proyekmu sudah pernah jalan:
GET /api/bukulewatBukuController(Controller, Service & Eloquent Laravel (#60))POST /api/login+ user uji + Sanctum (Auth API Dasar: Login & Kartu Anggota (#61))- Form Request / aturan validasi untuk slip buku (Request & Form Request: Menjaga Input API (#59))
Kalau salah satu hilang, jangan “loncat Capstone” — perbaiki fondasi dulu. Capstone hanya menyambung.
Loket tambah — method store
Buka notepad app\Http\Controllers\BukuController.php. Pastikan ada method store (nama boleh sama) yang menerima slip valid lalu menyimpan lewat Service/Eloquent yang sudah kamu punya di Controller, Service & Eloquent Laravel (#60). Contoh kerangka:
// Cuplikan BukuController — loket tambah buku
use App\Http\Requests\StoreBukuRequest; // sesuaikan nama Form Request-mu
use Illuminate\Http\JsonResponse;
public function store(StoreBukuRequest $request): JsonResponse
{
$data = $request->validated();
// Panggil Service / Model yang sudah kamu buat di #60
$buku = $this->bukuService->tambah($data);
// atau: $buku = Buku::query()->create($data);
return response()->json([
'message' => 'Buku ditambahkan',
'data' => $buku,
], 201);
}
Awam: sesuaikan nama class Form Request / Service dengan file di Explorer-mu. Intinya: satpam slip dulu -> baru tulis ke rak -> jawab JSON 201.
Jika Form Request belum ada, buat mengikuti Request & Form Request: Menjaga Input API (#59) (misalnya php artisan make:request StoreBukuRequest), lalu isi aturan judul / penulis required string.
Sambungkan pintu di routes
Buka notepad routes\web.php. Pastikan tiga pintu Capstone terdaftar (login dari Auth API Dasar: Login & Kartu Anggota (#61) boleh sudah ada):
// Cuplikan routes/web.php — Capstone baca + login + tambah
use App\Http\Controllers\AuthController;
use App\Http\Controllers\BukuController;
Route::get('/api/buku', [BukuController::class, 'index']);
Route::post('/api/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::get('/api/saya', [AuthController::class, 'saya']);
Route::post('/api/buku', [BukuController::class, 'store']);
});
Simpan. Pastikan serve masih hidup di terminal pertama.
Awam: GET daftar di luar satpam kartu. POST tambah di dalam auth:sanctum — tanpa Bearer sah = ditolak.
Cek izin api/* — supaya POST tidak ditolak 419
Laravel punya satpam lobi bawaan bernama CSRF yang melindungi formulir web: ia menolak semua kiriman POST yang tidak datang dari halaman browser milik situs itu sendiri. Karena kita menguji POST /api/login dan POST /api/buku dari terminal (bukan browser), tanpa izin khusus jawabannya adalah {"message":"CSRF token mismatch."} dengan kode 419 — bukan token atau “Buku ditambahkan”.
Kalau di dalam withMiddleware sudah ada 'api/*' (dari Request & Form Request: Menjaga Input API (#59) atau Auth API Dasar: Login & Kartu Anggota (#61)) — lewati langkah ini.
Belum ada? Pastikan terminal kedua sudah di folder proyek (cd ke perpustakaan-api), lalu notepad bootstrap\app.php. Jangan menempel blok ->withMiddleware(...) baru di dalam fungsi yang sudah ada. Kerja di dalam fungsi itu: hapus // kalau masih ada, biarkan baris lain, lalu tempel hanya:
// Tempel di dalam withMiddleware yang sudah ada — jangan buat withMiddleware baru
$middleware->preventRequestForgery(except: [
'api/*',
]);
Hasil yang benar kira-kira begini (boleh ada baris lain di sekitarnya):
->withMiddleware(function (Middleware $middleware): void {
$middleware->preventRequestForgery(except: [
'api/*',
]);
})
Awam: except = “kecuali”. Di Laravel 13 nama resminya preventRequestForgery; nama lama validateCsrfTokens masih sama artinya.
Setiap kali menyimpan bootstrap\app.php, matikan serve di terminal pertama (Ctrl+C) lalu php artisan serve lagi.
Tenang, kartunya tetap aman. Pagar yang menjaga POST /api/buku adalah petugas kartu Sanctum (auth:sanctum) — CSRF itu satpam lobi untuk formulir browser, jenis yang berbeda.
Uji Capstone di terminal kedua
Jangan andalkan bilah alamat browser untuk POST. Ikuti pola uji di Request & Form Request: Menjaga Input API (#59) dan Auth API Dasar: Login & Kartu Anggota (#61).
Pastikan user uji masih ada (satu tembakan, bukan chat panjang):
php artisan tinker --execute="\App\Models\User::updateOrCreate(['email'=>'staf@perpustakaan.test'], ['name'=>'Staf Mini','password'=>bcrypt('password')]);"
Opsi A — curl.exe (Windows 10/11 biasanya sudah punya; ketik curl.exe agar tidak tertukar di PowerShell):
1) Login — ambil token
curl.exe -s -X POST http://127.0.0.1:8000/api/login ^
-H "Content-Type: application/json" ^
-H "Accept: application/json" ^
-d "{\"email\":\"staf@perpustakaan.test\",\"password\":\"password\"}"
Awam — salin token: di jawaban JSON cari kunci "token". Salin hanya string di antara tanda kutip. Jangan salin kata Bearer dari JSON — kata Bearer ditulis di header. Ganti GANTI_DENGAN_TOKEN di bawah.
Awam — cara salin teks dari terminal Windows: blok teks dengan klik kiri lalu tahan sambil digeser (klik-drag), lepas tombol mouse untuk menyalin otomatis. Tempel dengan klik kanan di jendela terminal (bukan Ctrl+V, terminal bawaan Windows kadang tidak mendukungnya).
2) Tambah tanpa kartu — harus ditolak
curl.exe -s -X POST http://127.0.0.1:8000/api/buku ^
-H "Content-Type: application/json" ^
-H "Accept: application/json" ^
-d "{\"judul\":\"Laskar Pelangi\",\"penulis\":\"Andrea Hirata\"}"
Kamu harus melihat “Belum diizinkan” / unauthenticated — bukan “Buku ditambahkan”.
3) Tambah dengan kartu — harus 201
curl.exe -s -X POST http://127.0.0.1:8000/api/buku ^
-H "Content-Type: application/json" ^
-H "Accept: application/json" ^
-H "Authorization: Bearer GANTI_DENGAN_TOKEN" ^
-d "{\"judul\":\"Laskar Pelangi\",\"penulis\":\"Andrea Hirata\"}"
4) Baca katalog — buku baru harus terlihat
curl.exe -s http://127.0.0.1:8000/api/buku ^
-H "Accept: application/json"
Opsi B — PowerShell (kalau lebih nyaman menempel header Bearer):
$login = Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/api/login `
-ContentType "application/json" `
-Body '{"email":"staf@perpustakaan.test","password":"password"}'
$token = $login.token
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/api/buku `
-ContentType "application/json" `
-Headers @{ Authorization = "Bearer $token"; Accept = "application/json" } `
-Body '{"judul":"Laskar Pelangi","penulis":"Andrea Hirata"}'
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/buku -Headers @{ Accept = "application/json" }
Opsi C — Postman / Insomnia (alat berjendela): method POST, URL http://127.0.0.1:8000/api/buku, header Authorization type Bearer Token, body JSON judul+penulis. Sama hasilnya — pilih yang paling nyaman.
Pola Dasar
Urutan Capstone yang aman: (1) nyalakan serve di terminal 1 · (2) pastikan login & GET daftar pernah OK · (3) pasang store + Form Request · (4) bungkus POST /api/buku dengan auth:sanctum · (5) uji: tanpa kartu gagal -> dengan kartu 201 -> GET melihat buku baru.
Awam: jangan menambah pintu ubah/hapus dulu. Capstone hari ini = baca + login + tambah saja.
File contoh — simulasi alur Capstone
Simpan sebagai laravel_capstone_api_perpustakaan_demo.php lalu jalankan: php laravel_capstone_api_perpustakaan_demo.php. Ini bukan Laravel sungguhan — hanya meniru tiga pintu agar alur terasa.
<?php
declare(strict_types=1);
/**
* laravel_capstone_api_perpustakaan_demo.php
* Simulasi Capstone: baca (publik) + login + tambah (ber-kartu).
*/
function demo(): void
{
$katalog = [
['id' => 1, 'judul' => 'Bumi', 'penulis' => 'Tere Liye'],
];
$kartuSah = 'kartu-staf-contoh';
echo "1) GET /api/buku (publik)\n";
echo json_encode(['message' => 'Daftar buku', 'data' => $katalog], JSON_UNESCAPED_UNICODE), PHP_EOL;
echo "2) POST /api/login -> token\n";
echo json_encode(['message' => 'Login berhasil', 'token' => $kartuSah], JSON_UNESCAPED_UNICODE), PHP_EOL;
echo "3) POST /api/buku tanpa kartu -> 401\n";
echo json_encode(['message' => 'Belum diizinkan'], JSON_UNESCAPED_UNICODE), PHP_EOL;
echo "4) POST /api/buku dengan Bearer -> 201\n";
$baru = ['id' => 2, 'judul' => 'Laskar Pelangi', 'penulis' => 'Andrea Hirata'];
$katalog[] = $baru;
echo json_encode(['message' => 'Buku ditambahkan', 'data' => $baru], JSON_UNESCAPED_UNICODE), PHP_EOL;
echo "5) GET /api/buku lagi\n";
echo json_encode(['message' => 'Daftar buku', 'data' => $katalog], JSON_UNESCAPED_UNICODE), PHP_EOL;
echo PHP_EOL, "Langkah sungguhan: serve -> login curl -> Bearer POST /api/buku -> GET daftar.", PHP_EOL;
}
demo();
Awam: declare(strict_types=1); = PHP lebih ketat soal tipe data di file contoh. Di Laravel sungguhan, kartu = token Sanctum, bukan string hard-code.
Kesalahan umum
- Jawaban
CSRF token mismatch/ kode 419 — izinapi/*dibootstrap\app.phpbelum dipasang (atau baris lain diwithMiddlewareterlanjur dihapus), atauservebelum dinyalakan ulang setelah file itu disimpan. - POST tambah dari bilah alamat browser — browser biasa GET. Pakai terminal kedua +
curl.exe/ PowerShell / Postman. - Lupa header Accept — tambahkan
Accept: application/jsonsupaya pesan error jelas (bukan halaman HTML). - Token salah salin — salin hanya nilai
"token"; jangan dobel kata Bearer; jangan ada spasi di ujung. - POST /api/buku di luar middleware — tanpa
auth:sanctum, siapa saja bisa menambah. Capstone wajib satpam kartu. - Serve mati di terminal 1 — semua uji di terminal 2 akan gagal koneksi. Nyalakan lagi
php artisan serve. - Terminal dari Start Menu — PATH PHP/Composer hilang. Pakai Terminal Laragon / Shell XAMPP.
Latihan
- Uji POST tambah tanpa Bearer — pastikan ditolak.
- Login, salin token, tambah satu buku, lalu GET daftar — pastikan judul baru ada.
- Coba slip kosong (
{}) dengan Bearer — pastikan satpam Form Request menolak (bukan 201). - (Opsional) Tambah buku kedua dengan judul beda; pastikan GET menampilkan keduanya.
FAQ
Apa bedanya Capstone dengan Auth API Dasar?
Auth API Dasar: Login & Kartu Anggota (#61) fokus kartu + pintu /api/saya. Capstone memakai kartu itu untuk menambah buku, plus memastikan baca katalog tetap publik.
Token yang mana yang disalin?
Hanya string di kunci "token" pada jawaban login. Panjang, tanpa spasi. Lalu tulis: Authorization: Bearer + string itu.
Terminal mana yang dipakai?
Terminal 1: serve. Terminal 2: login, tambah, baca. Editor: route + store. Browser: opsional cek lampu.
Kenapa masih Shell XAMPP / Laragon?
Agar PATH PHP sama seperti saat proyek dibuat. CMD dari Start Menu sering “php tidak dikenal”.
Apakah perlu Composer baru?
Tidak, jika Sanctum sudah dari Auth API Dasar: Login & Kartu Anggota (#61). Kalau belum — install-dari-nol di sana dulu.
Kapan ubah & hapus?
Lanjut ke CRUD API Buku: Ubah & Hapus (#63) — setelah Capstone ini nyaman.
Ringkasan
#62 (ini) merakit tiga pintu: baca katalog (publik), login (kartu), tambah buku (ber-kartu + slip valid). Fondasi datang dari Auth API Dasar: Login & Kartu Anggota (#61), Controller, Service & Eloquent Laravel (#60), dan Request & Form Request: Menjaga Input API (#59).
Ke mana setelah ini?
Berikutnya: CRUD API Buku: Ubah & Hapus (#63) — supaya staf bisa memperbaiki atau menghapus entri dengan kartu yang sama.
Seri 4 progress: langkah #62 (ini) · 7/8 jalur Laravel · prasyarat: Auth API Dasar: Login & Kartu Anggota (#61) LIVE. Berikutnya: CRUD API Buku: Ubah & Hapus (#63).