<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Muhammad Dhiyaul Atha</title>
    <description>The latest articles on Forem by Muhammad Dhiyaul Atha (@bangkah).</description>
    <link>https://forem.com/bangkah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3665512%2Fdc6c5db5-91c9-4887-a5c6-33c8db391e07.jpeg</url>
      <title>Forem: Muhammad Dhiyaul Atha</title>
      <link>https://forem.com/bangkah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bangkah"/>
    <language>en</language>
    <item>
      <title>Implementasi Kea DHCPv4 pada RHEL 10: Solusi Modern Pengelolaan Jaringan</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Thu, 30 Apr 2026 11:31:39 +0000</pubDate>
      <link>https://forem.com/bangkah/implementasi-kea-dhcpv4-pada-rhel-10-solusi-modern-pengelolaan-jaringan-23o7</link>
      <guid>https://forem.com/bangkah/implementasi-kea-dhcpv4-pada-rhel-10-solusi-modern-pengelolaan-jaringan-23o7</guid>
      <description>&lt;h3&gt;
  
  
  1. Pendahuluan
&lt;/h3&gt;

&lt;p&gt;Kea mulai diadopsi sebagai pengganti ISC DHCP dengan arsitektur yang lebih modern. Kea menawarkan performa lebih tinggi dan struktur konfigurasi berbasis JSON yang lebih modular. Artikel ini mendokumentasikan langkah-langkah konfigurasi Kea di lingkungan virtual (VirtualBox) dengan client Windows 10.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Topologi &amp;amp; Skenario Jaringan
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Server (RHEL 10)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Adapter 1: NAT (Akses Internet)&lt;/li&gt;
&lt;li&gt;  Adapter 2: Internal Network (&lt;code&gt;enp0s8&lt;/code&gt;) - IP Statis: &lt;code&gt;10.0.2.1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Client (Windows 10)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Adapter 1: Internal Network - DHCP Client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Konfigurasi Interface Server
&lt;/h3&gt;

&lt;p&gt;Sebelum menjalankan Kea, interface yang mengarah ke client harus memiliki IP statis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Menambahkan IP statis ke interface internal&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 10.0.2.1/24 dev enp0s8
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;enp0s8 up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6r4joipaqmj42y9aewx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6r4joipaqmj42y9aewx.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Konfigurasi Kea DHCPv4
&lt;/h3&gt;

&lt;p&gt;Edit file &lt;code&gt;/etc/kea/kea-dhcp4.conf&lt;/code&gt;. Fokus utama adalah mengarahkan &lt;code&gt;interfaces&lt;/code&gt; ke &lt;code&gt;enp0s8&lt;/code&gt; dan menentukan &lt;code&gt;pools&lt;/code&gt; alamat IP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"Dhcp4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"interfaces-config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"interfaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"enp0s8"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lease-database"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"memfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/var/lib/kea/kea-leases4.csv"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subnet4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"subnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.0.2.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.0.2.100 - 10.0.2.200"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"option-data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"routers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.0.2.1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"domain-name-servers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8.8.8.8, 8.8.4.4"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7fke9pub51ygaiemt8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7fke9pub51ygaiemt8m.png" alt=" " width="399" height="397"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5. Keamanan &amp;amp; Aktivasi Service
&lt;/h3&gt;

&lt;p&gt;Membuka port DHCP pada firewall dan merestart service Kea.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Konfigurasi Firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dhcp &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;

&lt;span class="c"&gt;# Restart Service&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart kea-dhcp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqemfvoa4yphodur24pg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqemfvoa4yphodur24pg.png" alt=" " width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  6. Pengujian pada Client
&lt;/h3&gt;

&lt;p&gt;Pada client Windows 10, lakukan pembaruan IP melalui Command Prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ipconfig /release
ipconfig /renew
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fml0ykos897ksoz2h82rh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fml0ykos897ksoz2h82rh.png" alt=" " width="552" height="224"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  7. Analisis Log &amp;amp; Database Lease
&lt;/h3&gt;

&lt;p&gt;Verifikasi terakhir adalah memeriksa apakah server mencatat penyewaan IP tersebut dalam database lokal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Melihat log aktivitas DORA secara real-time&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; kea-dhcp4 &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# Melihat database penyewaan IP&lt;/span&gt;
&lt;span class="nb"&gt;sudo cat&lt;/span&gt; /var/lib/kea/kea-leases4.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg03f0b41kssesisz80ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg03f0b41kssesisz80ae.png" alt=" " width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Kesimpulan
&lt;/h3&gt;

&lt;p&gt;Keberhasilan implementasi Kea DHCP sangat bergantung pada ketepatan penentuan interface fisik dan pengaturan IP statis pada sisi server. Dengan berpindah ke Kea, administrator jaringan mendapatkan kontrol lebih baik melalui struktur data JSON yang rapi.&lt;/p&gt;

</description>
      <category>rhel</category>
      <category>dhcp</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>Setup Identity Management (FreeIPA) di RHEL 10: Fondasi Infrastruktur Server Terpusat</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Wed, 29 Apr 2026 15:21:59 +0000</pubDate>
      <link>https://forem.com/bangkah/setup-ad-ds-di-rhel-10-membangun-fondasi-infrastruktur-server-terpusat-598m</link>
      <guid>https://forem.com/bangkah/setup-ad-ds-di-rhel-10-membangun-fondasi-infrastruktur-server-terpusat-598m</guid>
      <description>&lt;p&gt;Di lingkungan enterprise, manajemen identitas terpusat adalah komponen penting untuk menjaga keamanan dan skalabilitas sistem. Jika di ekosistem Windows kita mengenal Active Directory Domain Services (AD DS), maka di dunia Linux tersedia solusi setara yaitu Identity Management (IdM) berbasis FreeIPA.&lt;/p&gt;

&lt;p&gt;Pada artikel ini, saya akan membagikan pengalaman melakukan deployment FreeIPA di RHEL 10, lengkap dengan troubleshooting yang saya temui.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Environment Setup
&lt;/h3&gt;

&lt;p&gt;Untuk tutorial ini, saya menggunakan spesifikasi sistem berikut agar performa &lt;em&gt;Identity Management&lt;/em&gt; tetap stabil:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;OS:&lt;/strong&gt; Red Hat Enterprise Linux 10.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hardware:&lt;/strong&gt; Laptop dengan Intel i7-14650HX dan RTX 4050.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Network:&lt;/strong&gt; Pastikan sistem menggunakan IP statis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ti5theh6glkzc8wk2w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ti5theh6glkzc8wk2w4.png" alt=" " width="773" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The FQDN Rule: Don't Get Stuck!
&lt;/h3&gt;

&lt;p&gt;Salah satu syarat wajib untuk setup "AD DS" versi Linux ini adalah penggunaan &lt;strong&gt;Fully Qualified Domain Name (FQDN)&lt;/strong&gt;. Installer tidak akan menerima nama tunggal karena sistem identitas seperti Kerberos membutuhkan domain yang lengkap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Masalah:&lt;/strong&gt; Menggunakan nama seperti &lt;code&gt;atha&lt;/code&gt; akan memicu error &lt;code&gt;must be fully-qualified&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Solusi:&lt;/strong&gt; Set hostname dengan format &lt;code&gt;&amp;lt;hostname&amp;gt;.&amp;lt;domain&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;hostnamectl set-hostname server.atha.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfq7saxtq9agxmj8813t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfq7saxtq9agxmj8813t.png" alt=" " width="600" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Step-by-Step Installation
&lt;/h3&gt;

&lt;p&gt;Gunakan perintah berikut untuk memulai instalasi server beserta DNS-nya. Saya sangat menyarankan menentukan &lt;em&gt;forwarder&lt;/em&gt; secara eksplisit untuk menghindari masalah resolusi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ipa-server-install &lt;span class="nt"&gt;--setup-dns&lt;/span&gt; &lt;span class="nt"&gt;--forwarder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.1.1.1 &lt;span class="nt"&gt;--forwarder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wrt4jmqpc7377zs217s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wrt4jmqpc7377zs217s.png" alt=" " width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips Tambahan:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;NetBIOS:&lt;/strong&gt; Default-nya adalah &lt;code&gt;ATHA&lt;/code&gt;, ini berguna untuk integrasi dengan sistem Windows.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;NTP:&lt;/strong&gt; Biarkan menggunakan pool bawaan sistem kecuali Anda memiliki server waktu khusus.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Troubleshooting: Belajar dari Kesalahan
&lt;/h3&gt;

&lt;p&gt;Selama proses &lt;em&gt;sharing&lt;/em&gt; ini, ada beberapa kendala yang sempat saya alami dan bisa menjadi pelajaran buat teman-teman:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;DNS Timeout:&lt;/strong&gt; Jika installer gagal saat validasi &lt;em&gt;forwarder&lt;/em&gt;, biasanya ada masalah pada kueri IPv6 di jaringan Anda. Menggunakan flag &lt;code&gt;--forwarder&lt;/code&gt; manual adalah solusinya.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The "yes" Confirmation:&lt;/strong&gt; Jangan terkecoh di akhir ringkasan konfigurasi. Sistem menunggu input &lt;strong&gt;&lt;code&gt;yes&lt;/code&gt;&lt;/strong&gt; secara eksplisit. Jika hanya ditekan Enter, instalasi akan otomatis batal (&lt;em&gt;Aborted&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4glebmtkpxtopoylg5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4glebmtkpxtopoylg5c.png" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Final Steps &amp;amp; Verification
&lt;/h3&gt;

&lt;p&gt;Setelah instalasi selesai, buka akses layanan pada firewall agar sistem berjalan lancar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;freeipa-ldap,freeipa-ldaps,dns,ntp,http,https,kerberos&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gunakan perintah &lt;code&gt;kinit admin&lt;/code&gt; untuk memverifikasi tiket Kerberos Anda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0clry2t01retc7x0yg82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0clry2t01retc7x0yg82.png" alt=" " width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Membangun sistem identitas terpusat dengan FreeIPA memberikan kontrol penuh atas keamanan jaringan. Sebagai mahasiswa Teknik Informatika yang fokus pada &lt;em&gt;Backend&lt;/em&gt; dan &lt;em&gt;Security&lt;/em&gt;, pemahaman ini sangat membantu saya dalam mengelola infrastruktur server yang lebih profesional.&lt;/p&gt;

&lt;p&gt;Semoga tutorial ini bermanfaat bagi teman-teman yang juga sedang mengulik ekosistem RHEL!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>rhel</category>
      <category>devops</category>
      <category>freeipa</category>
    </item>
    <item>
      <title>I Built a Safety-First Workflow Layer for Pacman (ATHA)</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Tue, 31 Mar 2026 16:35:36 +0000</pubDate>
      <link>https://forem.com/bangkah/i-built-a-simple-pacman-aur-wrapper-for-arch-linux-atha-11bd</link>
      <guid>https://forem.com/bangkah/i-built-a-simple-pacman-aur-wrapper-for-arch-linux-atha-11bd</guid>
      <description>&lt;p&gt;Managing packages on Arch Linux is powerful, but sometimes it lacks visibility and safety.&lt;/p&gt;

&lt;p&gt;You run a command… and it just executes.&lt;/p&gt;

&lt;p&gt;No preview. No clear audit trail. No structured workflow.&lt;/p&gt;

&lt;p&gt;So I started building &lt;strong&gt;ATHA&lt;/strong&gt; — a safety-first workflow layer on top of pacman.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ATHA?
&lt;/h2&gt;

&lt;p&gt;ATHA is not a replacement for pacman.&lt;/p&gt;

&lt;p&gt;It tries to enhance it with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install planning (&lt;code&gt;--plan&lt;/code&gt;) before execution&lt;/li&gt;
&lt;li&gt;Dry-run support for safer operations&lt;/li&gt;
&lt;li&gt;Confirmation layers for critical actions&lt;/li&gt;
&lt;li&gt;Operation history with timeline view&lt;/li&gt;
&lt;li&gt;Built-in system diagnostics (&lt;code&gt;atha doctor&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make package operations more predictable, transparent, and auditable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Before installing a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;atha &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--plan&lt;/span&gt; neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a preview of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;li&gt;disk usage&lt;/li&gt;
&lt;li&gt;source (official repo or AUR)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Arch gives full control — but sometimes operations can feel a bit “blind”.&lt;/p&gt;

&lt;p&gt;ATHA is my attempt to improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safety → reduce accidental changes&lt;/li&gt;
&lt;li&gt;Transparency → understand what will happen&lt;/li&gt;
&lt;li&gt;Auditability → keep track of what happened&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;pacman&lt;/th&gt;
&lt;th&gt;yay&lt;/th&gt;
&lt;th&gt;ATHA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dry-run support&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install planning&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operation history&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow consistency&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yay &lt;span class="nt"&gt;-S&lt;/span&gt; atha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Bangkah/Atha" rel="noopener noreferrer"&gt;https://github.com/Bangkah/Atha&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AUR: &lt;a href="https://aur.archlinux.org/packages/atha" rel="noopener noreferrer"&gt;https://aur.archlinux.org/packages/atha&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💬 Feedback
&lt;/h2&gt;

&lt;p&gt;This project is still evolving and definitely not perfect.&lt;/p&gt;

&lt;p&gt;I’m sure there are things that can be improved — both in design and implementation.&lt;/p&gt;

&lt;p&gt;If you have feedback, criticism, or suggestions, I’d really appreciate hearing them.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>archlinux</category>
      <category>opensource</category>
      <category>cli</category>
    </item>
    <item>
      <title>My First Attempt at Building a Reasoning AI (ARC Prize 2026)</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Thu, 26 Mar 2026 07:28:57 +0000</pubDate>
      <link>https://forem.com/bangkah/my-first-attempt-at-building-a-reasoning-ai-arc-prize-2026-18dj</link>
      <guid>https://forem.com/bangkah/my-first-attempt-at-building-a-reasoning-ai-arc-prize-2026-18dj</guid>
      <description>&lt;p&gt;What if AI fails the moment the problem changes?&lt;/p&gt;

&lt;p&gt;Most AI systems today are great at recognizing patterns — but what happens when the problem itself is different from anything they’ve seen before?&lt;/p&gt;

&lt;p&gt;That’s exactly the challenge behind the ARC Prize 2026 on Kaggle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;I recently joined the ARC-AGI-2 competition on Kaggle, which challenges participants to build AI systems capable of solving problems they’ve never seen before.&lt;/p&gt;

&lt;p&gt;Unlike typical machine learning tasks, ARC is not about training on massive datasets.&lt;/p&gt;

&lt;p&gt;Instead, it focuses on something closer to human intelligence:&lt;br&gt;
&lt;strong&gt;reasoning and generalization.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  My First Approach (Baseline)
&lt;/h2&gt;

&lt;p&gt;To get started, I built a very simple baseline model.&lt;/p&gt;

&lt;p&gt;The goal was not to solve the problem yet — but to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the dataset structure&lt;/li&gt;
&lt;li&gt;Learn how submissions work&lt;/li&gt;
&lt;li&gt;Successfully make my first submission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the basic idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read input grid&lt;/li&gt;
&lt;li&gt;Generate output grid with the same shape&lt;/li&gt;
&lt;li&gt;Fill it with zeros&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes — it's intentionally simple.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code &amp;amp; Repository
&lt;/h2&gt;

&lt;p&gt;You can check my first implementation here: &lt;a href="https://github.com/Bangkah/arc-agi-learning" rel="noopener noreferrer"&gt;https://github.com/Bangkah/arc-agi-learning&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository documents my learning journey as I explore reasoning-based AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  First Submission (Kaggle)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy2p32yfqtlhigxsx467.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy2p32yfqtlhigxsx467.png" alt="Kaggle Submission Screenshot" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Start Simple?
&lt;/h2&gt;

&lt;p&gt;Because ARC is not about jumping into complex models.&lt;/p&gt;

&lt;p&gt;It’s about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding transformations&lt;/li&gt;
&lt;li&gt;Identifying patterns&lt;/li&gt;
&lt;li&gt;Building logic step-by-step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even advanced AI systems still struggle with ARC tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why ARC is Hard
&lt;/h2&gt;

&lt;p&gt;ARC tasks require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding abstract patterns&lt;/li&gt;
&lt;li&gt;Applying transformations&lt;/li&gt;
&lt;li&gt;Generalizing from very few examples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike traditional machine learning, there is no training phase with millions of samples.&lt;/p&gt;

&lt;p&gt;Each problem is a completely new challenge.&lt;/p&gt;




&lt;h2&gt;
  
  
  First Submission Result
&lt;/h2&gt;

&lt;p&gt;My first submission didn’t perform well — and that’s expected.&lt;/p&gt;

&lt;p&gt;The real goal was:&lt;br&gt;
✔ Understanding the pipeline&lt;br&gt;
✔ Getting familiar with the problem&lt;br&gt;
✔ Starting the journey&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Insight
&lt;/h2&gt;

&lt;p&gt;ARC is fundamentally different from most AI challenges.&lt;/p&gt;

&lt;p&gt;It’s not about:&lt;br&gt;
❌ memorizing patterns&lt;/p&gt;

&lt;p&gt;It’s about:&lt;br&gt;
✔ discovering rules&lt;br&gt;
✔ applying logic&lt;br&gt;
✔ adapting to new problems&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;My next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solve ARC tasks manually&lt;/li&gt;
&lt;li&gt;Build rule-based solutions&lt;/li&gt;
&lt;li&gt;Improve generalization step-by-step&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This is not just a competition — it’s a challenge to rethink how we approach AI.&lt;/p&gt;

&lt;p&gt;And I’m just getting started.&lt;/p&gt;




&lt;p&gt;Have you tried solving ARC tasks?&lt;/p&gt;

&lt;p&gt;I’d love to hear how others approach reasoning problems like this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>kaggle</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Tue, 24 Mar 2026 04:53:53 +0000</pubDate>
      <link>https://forem.com/bangkah/-36mp</link>
      <guid>https://forem.com/bangkah/-36mp</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7" class="crayons-story__hidden-navigation-link"&gt;My First Home Server Using a 12-Year-Old Laptop&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/bangkah" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3665512%2Fdc6c5db5-91c9-4887-a5c6-33c8db391e07.jpeg" alt="bangkah profile" class="crayons-avatar__image" width="800" height="599"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/bangkah" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Muhammad Dhiyaul Atha
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Muhammad Dhiyaul Atha
                
              
              &lt;div id="story-author-preview-content-3392551" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/bangkah" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3665512%2Fdc6c5db5-91c9-4887-a5c6-33c8db391e07.jpeg" class="crayons-avatar__image" alt="" width="800" height="599"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Muhammad Dhiyaul Atha&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7" id="article-link-3392551"&gt;
          My First Home Server Using a 12-Year-Old Laptop
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/linux"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;linux&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/homelab"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;homelab&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>linux</category>
      <category>devops</category>
      <category>productivity</category>
      <category>homelab</category>
    </item>
    <item>
      <title>My First Home Server Using a 12-Year-Old Laptop</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Tue, 24 Mar 2026 04:41:31 +0000</pubDate>
      <link>https://forem.com/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7</link>
      <guid>https://forem.com/bangkah/my-first-home-server-using-a-12-year-old-laptop-2eh7</guid>
      <description>&lt;h1&gt;
  
  
  When an Old Laptop Finds Its New Purpose
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Turning a 2012 MacBook Pro into My First Personal Server
&lt;/h2&gt;

&lt;p&gt;There was a 2012 MacBook Pro sitting in front of me.&lt;/p&gt;

&lt;p&gt;Not my main machine anymore.&lt;br&gt;
Definitely not fast by today’s standards.&lt;/p&gt;

&lt;p&gt;But that’s exactly where a simple question came up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“How far can this old laptop still be useful?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question led me to a small experiment —&lt;br&gt;
turning this old machine into a personal server and controlling it remotely via SSH from my main laptop.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why an Old Laptop?
&lt;/h2&gt;

&lt;p&gt;As a software engineering student, I started realizing something important:&lt;/p&gt;

&lt;p&gt;Learning about servers is not enough if it’s only theory.&lt;/p&gt;

&lt;p&gt;I can read documentation, watch tutorials, and follow guides —&lt;br&gt;
but there’s always a gap between &lt;em&gt;knowing&lt;/em&gt; and &lt;em&gt;actually experiencing it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;At the same time, I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 2012 MacBook Pro collecting dust&lt;/li&gt;
&lt;li&gt;A growing interest in Linux&lt;/li&gt;
&lt;li&gt;Curiosity about how servers actually work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of letting it sit unused, I turned it into a learning lab.&lt;/p&gt;


&lt;h2&gt;
  
  
  System Choice: Arch Linux on Old Hardware
&lt;/h2&gt;

&lt;p&gt;I chose &lt;strong&gt;Arch Linux&lt;/strong&gt; for this machine.&lt;/p&gt;

&lt;p&gt;Not because it’s easy — actually the opposite.&lt;/p&gt;

&lt;p&gt;But because I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A lightweight system&lt;/li&gt;
&lt;li&gt;Full control over everything installed&lt;/li&gt;
&lt;li&gt;A raw, hands-on learning experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For my main laptop, I use an Acer Nitro V16 running Garuda Linux —&lt;br&gt;
this is where I control everything from.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Struggles: Nothing Worked Perfectly
&lt;/h2&gt;

&lt;p&gt;Of course, things didn’t go smoothly at first.&lt;/p&gt;

&lt;p&gt;Here are some challenges I faced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚠️ Old hardware limitations (heat, performance)&lt;/li&gt;
&lt;li&gt;⚠️ Arch Linux setup complexity&lt;/li&gt;
&lt;li&gt;⚠️ Networking confusion (IP, services, firewall)&lt;/li&gt;
&lt;li&gt;⚠️ SSH failing due to small misconfigurations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There were frustrating moments, especially when:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Why is SSH installed but I still can’t connect?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But those were the moments where real learning happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading logs&lt;/li&gt;
&lt;li&gt;Understanding errors&lt;/li&gt;
&lt;li&gt;Not just copy-pasting commands&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Goal: More Than Just Remote Access
&lt;/h2&gt;

&lt;p&gt;My goal wasn’t just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Connect via SSH from another laptop”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wanted to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand how servers actually work&lt;/li&gt;
&lt;li&gt;Get comfortable working without a GUI&lt;/li&gt;
&lt;li&gt;Simulate a simple backend/DevOps workflow&lt;/li&gt;
&lt;li&gt;Build the habit of working remotely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This server became my personal lab —&lt;br&gt;
a safe place to break things and learn.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Breakthrough Moment
&lt;/h2&gt;

&lt;p&gt;The most satisfying moment?&lt;/p&gt;

&lt;p&gt;From my main laptop, I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;ssh&lt;/span&gt; atha@192.xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then…&lt;/p&gt;

&lt;p&gt;The terminal of the 2012 MacBook appeared on my screen.&lt;/p&gt;

&lt;p&gt;No GUI.&lt;br&gt;
No mouse.&lt;br&gt;
Just a terminal.&lt;/p&gt;

&lt;p&gt;But it felt like opening a door to a completely new world.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Can Do Now
&lt;/h2&gt;

&lt;p&gt;Now I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manage my server from my main laptop&lt;/li&gt;
&lt;li&gt;Install and configure services remotely&lt;/li&gt;
&lt;li&gt;Bring an old machine back to life&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this is just the beginning.&lt;/p&gt;

&lt;p&gt;Next, I plan to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a web server&lt;/li&gt;
&lt;li&gt;Building a simple API&lt;/li&gt;
&lt;li&gt;SSH hardening&lt;/li&gt;
&lt;li&gt;Small automation scripts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This experiment taught me something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Learning servers doesn’t have to be expensive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes, an old laptop and curiosity are enough.&lt;/p&gt;

&lt;p&gt;That 2012 MacBook Pro that once felt outdated&lt;br&gt;
now has a new role.&lt;/p&gt;

&lt;p&gt;Not as my main machine —&lt;br&gt;
but as a silent teacher, helping me understand systems, patience, and real learning.&lt;/p&gt;

&lt;p&gt;And this journey…&lt;/p&gt;

&lt;p&gt;is just getting started 🚀&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What about you?&lt;/strong&gt;&lt;br&gt;
Have you ever repurposed old hardware into something useful?&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>productivity</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Saya Membuat CLI Tool Jadwal Shalat dan Merilisnya ke Arch Linux AUR</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Wed, 18 Feb 2026 12:30:23 +0000</pubDate>
      <link>https://forem.com/bangkah/saya-membuat-cli-tool-jadwal-shalat-dan-merilisnya-ke-arch-linux-aur-352f</link>
      <guid>https://forem.com/bangkah/saya-membuat-cli-tool-jadwal-shalat-dan-merilisnya-ke-arch-linux-aur-352f</guid>
      <description>&lt;p&gt;Sebagai pengguna Linux dan seseorang yang sering bekerja di terminal, saya ingin bisa melihat jadwal shalat langsung dari CLI tanpa membuka browser atau aplikasi GUI.&lt;/p&gt;

&lt;p&gt;Dari kebutuhan sederhana itu, saya membuat sebuah tool bernama &lt;strong&gt;jadwal-shalat&lt;/strong&gt; — sebuah CLI tool profesional berbasis Python yang dapat menampilkan jadwal shalat secara otomatis berdasarkan lokasi pengguna.&lt;/p&gt;

&lt;p&gt;Sekarang tool ini sudah tersedia secara resmi di Arch Linux AUR.&lt;/p&gt;




&lt;h1&gt;
  
  
  Latar Belakang
&lt;/h1&gt;

&lt;p&gt;Banyak aplikasi jadwal shalat tersedia, tapi sebagian besar berbasis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile apps&lt;/li&gt;
&lt;li&gt;Website&lt;/li&gt;
&lt;li&gt;Aplikasi GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Masalahnya, bagi pengguna Linux yang sering bekerja di:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;terminal&lt;/li&gt;
&lt;li&gt;server&lt;/li&gt;
&lt;li&gt;SSH session&lt;/li&gt;
&lt;li&gt;environment minimal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;solusi tersebut tidak praktis.&lt;/p&gt;

&lt;p&gt;Saya ingin sesuatu yang:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ringan&lt;/li&gt;
&lt;li&gt;cepat&lt;/li&gt;
&lt;li&gt;otomatis&lt;/li&gt;
&lt;li&gt;dan native di terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maka saya membuat CLI tool ini.&lt;/p&gt;




&lt;h1&gt;
  
  
  Apa Itu jadwal-shalat?
&lt;/h1&gt;

&lt;p&gt;jadwal-shalat adalah CLI tool Python yang dapat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mendeteksi lokasi otomatis dari IP publik&lt;/li&gt;
&lt;li&gt;menentukan timezone secara akurat&lt;/li&gt;
&lt;li&gt;mengambil jadwal shalat dari API Aladhan (method Kemenag Indonesia)&lt;/li&gt;
&lt;li&gt;menampilkan jadwal secara rapi di terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tool ini dirancang khusus untuk pengguna Indonesia.&lt;/p&gt;




&lt;h1&gt;
  
  
  Fitur Utama
&lt;/h1&gt;

&lt;p&gt;Beberapa fitur yang tersedia saat ini:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deteksi IP publik otomatis&lt;/li&gt;
&lt;li&gt;Deteksi lokasi otomatis (kota, negara, koordinat, timezone)&lt;/li&gt;
&lt;li&gt;Fallback API lokasi jika layanan utama gagal&lt;/li&gt;
&lt;li&gt;Menggunakan API Aladhan (method=20/Kemenag Indonesia)&lt;/li&gt;
&lt;li&gt;Jadwal shalat lengkap&lt;/li&gt;
&lt;li&gt;Menampilkan waktu shalat berikutnya + countdown&lt;/li&gt;
&lt;li&gt;Output terminal rapi dengan alignment yang baik&lt;/li&gt;
&lt;li&gt;Error handling lengkap&lt;/li&gt;
&lt;li&gt;Timeout protection untuk API&lt;/li&gt;
&lt;li&gt;Support timezone akurat&lt;/li&gt;
&lt;li&gt;Siap packaging AUR dengan auto update&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Contoh Output
&lt;/h1&gt;

&lt;p&gt;Contoh ketika dijalankan:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7e9ybq3pcq2j3xufvpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7e9ybq3pcq2j3xufvpx.png" alt=" " width="624" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output difokuskan agar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mudah dibaca&lt;/li&gt;
&lt;li&gt;minimalis&lt;/li&gt;
&lt;li&gt;profesional&lt;/li&gt;
&lt;li&gt;cocok untuk penggunaan harian di terminal&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Instalasi via Arch Linux AUR
&lt;/h1&gt;

&lt;p&gt;Tool ini sekarang tersedia di AUR, sehingga instalasi sangat mudah:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yay -S jadwal-shalat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atau manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://aur.archlinux.org/jadwal-shalat.git
cd jadwal-shalat
makepkg -si
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sebagai maintainer AUR, saya juga mengatur auto-update menggunakan GitHub Actions.&lt;/p&gt;




&lt;h1&gt;
  
  
  Instalasi Manual
&lt;/h1&gt;

&lt;p&gt;Jika tidak menggunakan Arch Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Bangkah/jadwal-shalat.git
cd jadwal-shalat
chmod +x jadwal-shalat.py
./jadwal-shalat.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atau:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python jadwal-shalat.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Cara Kerja Tool Ini
&lt;/h1&gt;

&lt;p&gt;Secara sederhana:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mengambil IP publik user&lt;/li&gt;
&lt;li&gt;Mengubah IP menjadi lokasi geografis&lt;/li&gt;
&lt;li&gt;Menentukan timezone&lt;/li&gt;
&lt;li&gt;Mengambil jadwal shalat dari API Aladhan&lt;/li&gt;
&lt;li&gt;Menampilkan jadwal dan countdown&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Semua proses dilakukan secara otomatis.&lt;/p&gt;




&lt;h1&gt;
  
  
  Fokus pada Reliability
&lt;/h1&gt;

&lt;p&gt;Beberapa hal yang saya implementasikan untuk memastikan tool stabil:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fallback API jika layanan lokasi gagal&lt;/li&gt;
&lt;li&gt;timeout protection&lt;/li&gt;
&lt;li&gt;error handling jaringan&lt;/li&gt;
&lt;li&gt;parsing timezone akurat&lt;/li&gt;
&lt;li&gt;output formatting konsisten&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ini penting agar tool tetap berfungsi bahkan dalam kondisi jaringan tidak stabil.&lt;/p&gt;




&lt;h1&gt;
  
  
  Integrasi dengan Arch Linux Packaging
&lt;/h1&gt;

&lt;p&gt;Salah satu milestone terbesar project ini adalah berhasil dipublish ke Arch Linux AUR.&lt;/p&gt;

&lt;p&gt;Ini berarti:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user bisa install dengan yay&lt;/li&gt;
&lt;li&gt;update terdistribusi secara otomatis&lt;/li&gt;
&lt;li&gt;mengikuti standar packaging Linux&lt;/li&gt;
&lt;li&gt;tool menjadi lebih profesional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Saya juga mengintegrasikan GitHub Actions untuk membantu workflow update.&lt;/p&gt;




&lt;h1&gt;
  
  
  Roadmap ke Depan
&lt;/h1&gt;

&lt;p&gt;Beberapa fitur yang direncanakan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input manual kota&lt;/li&gt;
&lt;li&gt;input manual koordinat&lt;/li&gt;
&lt;li&gt;output JSON&lt;/li&gt;
&lt;li&gt;notifikasi waktu shalat&lt;/li&gt;
&lt;li&gt;packaging PyPI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tujuannya adalah membuat tool ini semakin fleksibel.&lt;/p&gt;




&lt;h1&gt;
  
  
  Kenapa Saya Membuat Project Ini?
&lt;/h1&gt;

&lt;p&gt;Selain kebutuhan pribadi, project ini juga menjadi sarana belajar tentang:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI development dengan Python&lt;/li&gt;
&lt;li&gt;API integration&lt;/li&gt;
&lt;li&gt;timezone handling&lt;/li&gt;
&lt;li&gt;Linux packaging (PKGBUILD)&lt;/li&gt;
&lt;li&gt;AUR maintenance&lt;/li&gt;
&lt;li&gt;CI/CD dengan GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Project kecil seperti ini sangat membantu meningkatkan skill sebagai developer.&lt;/p&gt;




&lt;h1&gt;
  
  
  Open Source dan Kontribusi
&lt;/h1&gt;

&lt;p&gt;Project ini open source dan tersedia di GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Bangkah/jadwal-shalat" rel="noopener noreferrer"&gt;https://github.com/Bangkah/jadwal-shalat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kontribusi sangat diterima.&lt;/p&gt;




&lt;h1&gt;
  
  
  Penutup
&lt;/h1&gt;

&lt;p&gt;Linux memiliki ekosistem CLI yang sangat kuat, dan saya percaya tool kecil seperti ini bisa meningkatkan produktivitas pengguna terminal.&lt;/p&gt;

&lt;p&gt;Jika kamu pengguna Arch Linux atau Linux secara umum, kamu bisa mencoba tool ini dan memberikan feedback.&lt;/p&gt;

</description>
      <category>aur</category>
      <category>python</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building Sentinel AI: A Cybersecurity CLI Powered by Copilot</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Sat, 14 Feb 2026 17:30:38 +0000</pubDate>
      <link>https://forem.com/bangkah/building-sentinel-ai-a-cybersecurity-cli-powered-by-copilot-35fh</link>
      <guid>https://forem.com/bangkah/building-sentinel-ai-a-cybersecurity-cli-powered-by-copilot-35fh</guid>
      <description>&lt;h1&gt;
  
  
  From Copilot Experiment to Production-Ready CLI: Building Sentinel AI
&lt;/h1&gt;

&lt;p&gt;Cybersecurity is no longer optional — every connected system is exposed to potential threats. While there are many enterprise-grade tools available, I wanted to understand how such tools work internally.&lt;/p&gt;

&lt;p&gt;So I built my own.&lt;/p&gt;

&lt;p&gt;Sentinel AI started as a small experiment using GitHub Copilot CLI. But through iteration, debugging, and production hardening, it evolved into a fully functional, production-ready cybersecurity CLI tool for Linux.&lt;/p&gt;

&lt;p&gt;This article explains the journey — from idea to production.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Idea
&lt;/h1&gt;

&lt;p&gt;Modern systems constantly create network connections — many legitimate, some suspicious. Most users never see what is happening behind the scenes.&lt;/p&gt;

&lt;p&gt;I wanted a tool that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show active network connections&lt;/li&gt;
&lt;li&gt;Identify suspicious behavior&lt;/li&gt;
&lt;li&gt;Assign risk scores&lt;/li&gt;
&lt;li&gt;Provide actionable summaries&lt;/li&gt;
&lt;li&gt;Work directly from the terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It needed to be fast, simple, and transparent.&lt;/p&gt;

&lt;p&gt;That’s how Sentinel AI was born.&lt;/p&gt;




&lt;h1&gt;
  
  
  How GitHub Copilot Accelerated Development
&lt;/h1&gt;

&lt;p&gt;GitHub Copilot CLI significantly accelerated development by helping generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular Python code structure&lt;/li&gt;
&lt;li&gt;CLI argument parsing using argparse&lt;/li&gt;
&lt;li&gt;Risk classification logic&lt;/li&gt;
&lt;li&gt;Error handling and logging&lt;/li&gt;
&lt;li&gt;Clean and readable code patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of spending hours writing boilerplate, I could focus on architecture and functionality.&lt;/p&gt;

&lt;p&gt;Copilot acted as a coding assistant — not a replacement — helping me move faster while maintaining control over the system design.&lt;/p&gt;




&lt;h1&gt;
  
  
  Architecture Overview
&lt;/h1&gt;

&lt;p&gt;Sentinel AI is built using a modular architecture:&lt;/p&gt;

&lt;p&gt;Core components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network Scanner — collects active connections&lt;/li&gt;
&lt;li&gt;Analyzer — evaluates connections and assigns risk scores&lt;/li&gt;
&lt;li&gt;Reporting Engine — summarizes system risk level&lt;/li&gt;
&lt;li&gt;CLI Interface — provides user interaction&lt;/li&gt;
&lt;li&gt;Logging System — records activity and errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;psutil&lt;/li&gt;
&lt;li&gt;colorama&lt;/li&gt;
&lt;li&gt;argparse&lt;/li&gt;
&lt;li&gt;autopep8&lt;/li&gt;
&lt;li&gt;GitHub Actions (CI/CD)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture ensures maintainability and extensibility.&lt;/p&gt;




&lt;h1&gt;
  
  
  Core Features
&lt;/h1&gt;

&lt;p&gt;Sentinel AI provides several security-focused capabilities:&lt;/p&gt;

&lt;h3&gt;
  
  
  Network Scanning
&lt;/h3&gt;

&lt;p&gt;Lists all active network connections with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protocol&lt;/li&gt;
&lt;li&gt;Local address&lt;/li&gt;
&lt;li&gt;Remote address&lt;/li&gt;
&lt;li&gt;Process ID&lt;/li&gt;
&lt;li&gt;Process name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Intelligent Risk Analysis
&lt;/h3&gt;

&lt;p&gt;Each connection is analyzed and assigned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Numeric risk score (0–100)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Risk level classification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LOW&lt;/li&gt;
&lt;li&gt;MEDIUM&lt;/li&gt;
&lt;li&gt;HIGH&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Explanation of the risk&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Proto  Local Address      Remote Address     PID   Process   Risk
TCP    192.168.1.10:54321 8.8.8.8:53        1234  python3   HIGH (87)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  System Risk Report
&lt;/h3&gt;

&lt;p&gt;Provides a system-level security overview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== Sentinel AI CLI Security Report ===
Total connections: 12
External connections: 3
High risk: 1
Medium risk: 2
Low risk: 9
Overall system risk: HIGH (72/100)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows users to understand their system security posture instantly.&lt;/p&gt;




&lt;h3&gt;
  
  
  System Information
&lt;/h3&gt;

&lt;p&gt;Displays system-level information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS&lt;/li&gt;
&lt;li&gt;Kernel version&lt;/li&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Hostname&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Developer Utilities
&lt;/h3&gt;

&lt;p&gt;Sentinel AI also includes developer-focused tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai debug file.py
sentinel-ai explain-code file.py
sentinel-ai improve-code file.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tools help developers analyze, debug, and improve Python code.&lt;/p&gt;




&lt;h1&gt;
  
  
  From Prototype to Production
&lt;/h1&gt;

&lt;p&gt;What started as a simple script evolved into a production-grade CLI tool.&lt;/p&gt;

&lt;p&gt;Key improvements included:&lt;/p&gt;

&lt;h3&gt;
  
  
  Modern Python Packaging
&lt;/h3&gt;

&lt;p&gt;Sentinel AI uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pyproject.toml&lt;/li&gt;
&lt;li&gt;Standardized project structure&lt;/li&gt;
&lt;li&gt;Proper dependency management&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;Using GitHub Actions, Sentinel AI now has automated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linting (PEP8 compliance)&lt;/li&gt;
&lt;li&gt;Build validation&lt;/li&gt;
&lt;li&gt;Test execution&lt;/li&gt;
&lt;li&gt;Release safety checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures every update maintains production quality.&lt;/p&gt;




&lt;h3&gt;
  
  
  Trusted Publishing to PyPI
&lt;/h3&gt;

&lt;p&gt;Sentinel AI uses secure Trusted Publishing, allowing automated and secure package releases.&lt;/p&gt;

&lt;p&gt;This eliminates manual credential handling and improves release security.&lt;/p&gt;




&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Sentinel AI is available on PyPI.&lt;/p&gt;

&lt;p&gt;Install using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install sentinel-ai-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentinel-ai report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And immediately see your system’s security overview.&lt;/p&gt;




&lt;h1&gt;
  
  
  Challenges and Lessons Learned
&lt;/h1&gt;

&lt;p&gt;Building Sentinel AI taught me several important engineering lessons:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. CI/CD Discipline
&lt;/h3&gt;

&lt;p&gt;Fixing lint errors, formatting issues, and pipeline failures helped reinforce professional development practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Production Packaging
&lt;/h3&gt;

&lt;p&gt;Using modern Python packaging standards improved maintainability and reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CLI Design Principles
&lt;/h3&gt;

&lt;p&gt;Designing a clean CLI interface requires careful planning to ensure usability and clarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Copilot as a Force Multiplier
&lt;/h3&gt;

&lt;p&gt;Copilot accelerated development — but debugging and refinement required human understanding.&lt;/p&gt;

&lt;p&gt;AI helped build faster, but engineering discipline made it production-ready.&lt;/p&gt;




&lt;h1&gt;
  
  
  Future Plans
&lt;/h1&gt;

&lt;p&gt;Planned improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arch Linux (AUR) package&lt;/li&gt;
&lt;li&gt;Docker image&lt;/li&gt;
&lt;li&gt;Real-time monitoring mode&lt;/li&gt;
&lt;li&gt;Threat intelligence integration&lt;/li&gt;
&lt;li&gt;Plugin system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sentinel AI will continue evolving.&lt;/p&gt;




&lt;h1&gt;
  
  
  Open Source and Availability
&lt;/h1&gt;

&lt;p&gt;GitHub Repository:&lt;br&gt;
&lt;a href="https://github.com/Bangkah/sentinel" rel="noopener noreferrer"&gt;https://github.com/Bangkah/sentinel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PyPI Package:&lt;br&gt;
&lt;a href="https://pypi.org/project/sentinel-ai-cli/" rel="noopener noreferrer"&gt;https://pypi.org/project/sentinel-ai-cli/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sentinel AI is fully open source and contributions are welcome.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Sentinel AI began as a simple experiment with GitHub Copilot CLI.&lt;/p&gt;

&lt;p&gt;Through iteration, debugging, CI/CD integration, and proper packaging, it became a production-ready cybersecurity tool.&lt;/p&gt;

&lt;p&gt;This project demonstrates how modern AI-assisted development, combined with engineering discipline, can accelerate the creation of real-world tools.&lt;/p&gt;

&lt;p&gt;Sentinel AI is not just a project — it is a foundation for building more advanced security tools in the future.&lt;/p&gt;




&lt;h1&gt;
  
  
  Author
&lt;/h1&gt;

&lt;p&gt;Muhammad Dhiyaul Atha&lt;br&gt;
Computer Science Student &amp;amp; Open Source Developer&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>devchallenge</category>
    </item>
    <item>
      <title>Saat Laptop Lama Menemukan Peran Barunya</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Fri, 30 Jan 2026 18:11:37 +0000</pubDate>
      <link>https://forem.com/bangkah/saat-laptop-lama-menemukan-peran-barunya-3pha</link>
      <guid>https://forem.com/bangkah/saat-laptop-lama-menemukan-peran-barunya-3pha</guid>
      <description>&lt;h1&gt;
  
  
  Mengubah MacBook Pro 2012 Menjadi Server Pribadi (Eksperimen Pertamaku)
&lt;/h1&gt;

&lt;p&gt;Ada satu MacBook Pro 2012 di hadapanku.&lt;br&gt;
Bukan laptop utama, performanya juga jelas sudah tertinggal jauh dibanding mesin-mesin modern. Tapi justru dari situ muncul satu pertanyaan sederhana:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Sejauh apa laptop lama ini masih bisa berguna?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pertanyaan itu akhirnya membawaku pada sebuah eksperimen kecil: &lt;strong&gt;mengubah MacBook Pro 2012 menjadi server pribadi&lt;/strong&gt;, lalu mengontrolnya dari laptop utamaku menggunakan &lt;strong&gt;SSH&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Latar Belakang: Kenapa Laptop Lama?
&lt;/h2&gt;

&lt;p&gt;Sebagai mahasiswa dan pembelajar di dunia software engineering, aku mulai sadar satu hal:&lt;br&gt;
&lt;strong&gt;belajar server tidak cukup hanya dari teori.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aku bisa membaca dokumentasi, menonton video, atau mengikuti tutorial, tapi tetap ada jarak antara “tahu” dan “pernah mengalami sendiri”.&lt;/p&gt;

&lt;p&gt;Di sisi lain, aku punya:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;MacBook Pro 2012&lt;/strong&gt; yang jarang dipakai&lt;/li&gt;
&lt;li&gt; ketertarikan besar pada Linux&lt;/li&gt;
&lt;li&gt; rasa penasaran tentang bagaimana server bekerja di dunia nyata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Daripada membiarkannya berdebu, aku memutuskan menjadikannya &lt;strong&gt;server eksperimen&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Pilihan Sistem: Arch Linux di Mesin Tua
&lt;/h2&gt;

&lt;p&gt;Aku memilih &lt;strong&gt;Arch Linux&lt;/strong&gt; untuk MacBook Pro 2012 ini.&lt;/p&gt;

&lt;p&gt;Bukan karena paling mudah — justru sebaliknya.&lt;br&gt;
Tapi karena aku ingin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sistem yang ringan&lt;/li&gt;
&lt;li&gt;kontrol penuh terhadap apa saja yang terpasang&lt;/li&gt;
&lt;li&gt;dan pengalaman belajar yang “apa adanya”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Untuk laptop utamaku, aku menggunakan &lt;strong&gt;Acer Nitro V16 dengan Garuda Linux&lt;/strong&gt;. Dari sinilah semua kontrol dilakukan.&lt;/p&gt;


&lt;h2&gt;
  
  
  Kendala: Tidak Semua Berjalan Mulus
&lt;/h2&gt;

&lt;p&gt;Tentu saja, eksperimen ini tidak langsung berjalan mulus.&lt;/p&gt;

&lt;p&gt;Beberapa kendala yang aku temui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚠️ &lt;strong&gt;Hardware lama&lt;/strong&gt;: kipas cepat panas, performa terbatas&lt;/li&gt;
&lt;li&gt;⚠️ Konfigurasi Arch Linux yang menuntut ketelitian&lt;/li&gt;
&lt;li&gt;⚠️ Networking yang awalnya membingungkan (IP, service, firewall)&lt;/li&gt;
&lt;li&gt;⚠️ SSH yang sempat gagal konek karena kesalahan kecil&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ada momen frustrasi, terutama saat:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Kenapa sudah install SSH tapi tetap tidak bisa diakses?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Namun justru di titik-titik inilah aku benar-benar belajar:&lt;br&gt;
membaca log, memahami error, dan tidak asal copy–paste perintah.&lt;/p&gt;


&lt;h2&gt;
  
  
  Tujuan: Bukan Sekadar Bisa Remote
&lt;/h2&gt;

&lt;p&gt;Tujuanku bukan hanya:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“bisa login SSH dari laptop lain”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lebih dari itu, aku ingin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memahami &lt;strong&gt;konsep server secara nyata&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;membiasakan diri mengelola sistem tanpa GUI&lt;/li&gt;
&lt;li&gt;mensimulasikan workflow backend &amp;amp; DevOps sederhana&lt;/li&gt;
&lt;li&gt;dan melatih kebiasaan bekerja secara remote&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Server ini aku anggap sebagai &lt;strong&gt;laboratorium pribadi&lt;/strong&gt;, tempat aman untuk salah dan belajar.&lt;/p&gt;


&lt;h2&gt;
  
  
  Progres: Saat SSH Akhirnya Berhasil
&lt;/h2&gt;

&lt;p&gt;Momen paling memuaskan adalah saat dari Acer Nitro V16 aku menjalankan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh atha@192.xxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lalu…&lt;br&gt;
terminal MacBook Pro 2012 muncul di layarku.&lt;/p&gt;

&lt;p&gt;Tidak ada tampilan grafis.&lt;br&gt;
Tidak ada mouse.&lt;br&gt;
Hanya terminal — tapi rasanya seperti membuka pintu ke dunia baru.&lt;/p&gt;

&lt;p&gt;Sekarang aku bisa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mengelola server dari laptop utama&lt;/li&gt;
&lt;li&gt;install service tanpa menyentuh fisik server&lt;/li&gt;
&lt;li&gt;menjadikan MacBook lama sebagai mesin yang “hidup kembali”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dari sini, rencananya akan berlanjut ke:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;web server&lt;/li&gt;
&lt;li&gt;API sederhana&lt;/li&gt;
&lt;li&gt;hardening SSH&lt;/li&gt;
&lt;li&gt;dan mungkin automasi kecil-kecilan&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Penutup
&lt;/h2&gt;

&lt;p&gt;Eksperimen ini mengajarkanku satu hal penting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Belajar server tidak harus mahal.&lt;br&gt;
Kadang, laptop lama dan rasa penasaran sudah cukup.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;MacBook Pro 2012 yang dulu terasa usang, kini punya peran baru.&lt;br&gt;
Bukan sebagai mesin utama, tapi sebagai &lt;strong&gt;guru diam-diam&lt;/strong&gt; yang mengajarkanku tentang sistem, kesabaran, dan proses belajar yang sebenarnya.&lt;/p&gt;

&lt;p&gt;Dan perjalanan ini… baru saja dimulai.&lt;/p&gt;




</description>
      <category>devops</category>
      <category>linux</category>
      <category>learning</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Membuat API CRUD di Laravel dengan Sanctum (Step by Step)</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Sun, 11 Jan 2026 15:00:37 +0000</pubDate>
      <link>https://forem.com/bangkah/membuat-api-crud-di-laravel-dengan-sanctum-step-by-step-id</link>
      <guid>https://forem.com/bangkah/membuat-api-crud-di-laravel-dengan-sanctum-step-by-step-id</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Pernah nggak, frontend kamu butuh data dari backend Laravel, tapi API-nya belum aman? Di artikel ini, kamu akan belajar bikin API CRUD yang hanya bisa diakses user terautentikasi pakai Sanctum."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Kenapa Harus Pakai Sanctum untuk API CRUD?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Data lebih aman, hanya user login yang bisa akses&lt;/li&gt;
&lt;li&gt;Cocok untuk SPA, mobile app, dan aplikasi modern&lt;/li&gt;
&lt;li&gt;Mudah diintegrasikan dengan frontend (React, Vue, dsb)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Studi Kasus: API Artikel (CRUD + Auth)
&lt;/h2&gt;

&lt;p&gt;Kita akan membuat API CRUD Artikel yang hanya bisa diakses user yang sudah login menggunakan Laravel Sanctum.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Setup Project Laravel &amp;amp; Sanctum
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt; laravel/laravel belajar-api
&lt;span class="nb"&gt;cd &lt;/span&gt;belajar-api
composer require laravel/sanctum
php artisan vendor:publish &lt;span class="nt"&gt;--provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Laravel&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;anctum&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;anctumServiceProvider"&lt;/span&gt;
php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tambahkan middleware Sanctum di &lt;code&gt;app/Http/Kernel.php&lt;/code&gt; pada group &lt;code&gt;api&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'api'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'throttle:api'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;\Illuminate\Routing\Middleware\SubstituteBindings&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Setup Model User &amp;amp; Artikel (Ownership Data)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;

&lt;p&gt;Pastikan model &lt;code&gt;User&lt;/code&gt; pakai trait &lt;code&gt;HasApiTokens&lt;/code&gt; dan relasi ke artikel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Sanctum\HasApiTokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasApiTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Notifiable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Artikel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:model Article &lt;span class="nt"&gt;-m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cascadeOnDelete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jalankan migrasi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Di model &lt;code&gt;Article.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Auth Controller (Register, Login, Logout)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:controller Api/AuthController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contoh fungsi register, login, logout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|email|unique:users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|min:6'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'api-token'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$credentials&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'api-token'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;currentAccessToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Logged out'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Article Controller (CRUD)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:controller Api/ArticleController &lt;span class="nt"&gt;--resource&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contoh fungsi CRUD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'content'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// Ownership: artikel milik user login&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Authorization: hanya pemilik yang boleh akses&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'content'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5: Route API
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;routes/api.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Controllers\Api\AuthController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Controllers\Api\ArticleController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'register'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'register'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth:sanctum'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logout'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'logout'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;apiResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArticleController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6: Testing API CRUD dengan Postman
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Fungsi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;/api/articles&lt;/td&gt;
&lt;td&gt;List semua artikel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;/api/articles&lt;/td&gt;
&lt;td&gt;Simpan artikel baru&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Detail artikel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Update artikel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Hapus artikel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Jangan lupa kirim token di header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer {token}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Contoh Response JSON
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Belajar Laravel API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laravel API itu powerful..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-11"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Kenapa API Ini Aman?
&lt;/h2&gt;

&lt;p&gt;Dengan Sanctum + &lt;code&gt;auth:sanctum&lt;/code&gt;, API ini tidak bisa diakses tanpa token. Setiap request divalidasi berdasarkan user yang login, dan hanya pemilik data yang bisa mengakses/mengubah artikelnya sendiri.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kalau Mau Dipakai di Frontend
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React: simpan token di localStorage, kirim di header Authorization setiap request&lt;/li&gt;
&lt;li&gt;Axios: gunakan interceptor untuk otomatis attach token&lt;/li&gt;
&lt;li&gt;Jangan expose token di public repo!&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Error Handling &amp;amp; Status Code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;201 Created: Data berhasil dibuat&lt;/li&gt;
&lt;li&gt;200 OK: Data berhasil diambil/diupdate&lt;/li&gt;
&lt;li&gt;204 No Content: Data dihapus&lt;/li&gt;
&lt;li&gt;401 Unauthorized: Token salah/expired&lt;/li&gt;
&lt;li&gt;404 Not Found: Data tidak ditemukan&lt;/li&gt;
&lt;li&gt;422 Unprocessable Entity: Validasi gagal&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistake Pemula
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lupa migrate/publish Sanctum&lt;/li&gt;
&lt;li&gt;Lupa middleware &lt;code&gt;auth:sanctum&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Token tidak dikirim di header&lt;/li&gt;
&lt;li&gt;Lupa set &lt;code&gt;Accept: application/json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Salah endpoint (POST login, bukan GET)&lt;/li&gt;
&lt;li&gt;Salah group route (harus di dalam middleware)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API Resource (response lebih rapi)&lt;/li&gt;
&lt;li&gt;Pagination &amp;amp; filtering&lt;/li&gt;
&lt;li&gt;Role &amp;amp; permission&lt;/li&gt;
&lt;li&gt;Testing dengan Thunder Client&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Yuk Diskusi &amp;amp; Share!
&lt;/h2&gt;

&lt;p&gt;Kalau kamu stuck di step tertentu, tulis di komentar ya! Share juga pengalaman kamu bikin API CRUD Laravel, atau request topik lanjutan (API Resource, pagination, dsb).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Referensi:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs/10.x/sanctum" rel="noopener noreferrer"&gt;Laravel Sanctum Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs/10.x/eloquent-resources" rel="noopener noreferrer"&gt;Laravel API Resource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs/10.x/controllers#resource-controllers" rel="noopener noreferrer"&gt;Laravel CRUD API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>crud</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Laravel API Authentication dengan Sanctum</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Sun, 11 Jan 2026 14:50:53 +0000</pubDate>
      <link>https://forem.com/bangkah/laravel-api-authentication-dengan-sanctum-5fm</link>
      <guid>https://forem.com/bangkah/laravel-api-authentication-dengan-sanctum-5fm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Pernah nggak, API kamu bisa diakses siapa saja tanpa login? Atau frontend sudah jadi, tapi bingung gimana cara login ke backend Laravel? Di sinilah Laravel Sanctum jadi solusi autentikasi API yang simpel dan powerful."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Kenapa Perlu Autentikasi API?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Melindungi data dari akses sembarangan&lt;/li&gt;
&lt;li&gt;Wajib untuk aplikasi SPA, mobile, dan public API&lt;/li&gt;
&lt;li&gt;User harus login untuk akses data pribadi&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cara Kerja Sanctum (Token Based Auth)
&lt;/h2&gt;

&lt;p&gt;Laravel Sanctum menggunakan token-based authentication. Artinya, setelah login, user akan mendapatkan token yang harus dikirim di setiap request API melalui header Authorization. Ini membuat API lebih aman dan mudah diintegrasikan dengan frontend atau mobile app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Studi Kasus: API Artikel dengan Login
&lt;/h2&gt;

&lt;p&gt;Di artikel ini, kita akan membuat API Artikel yang hanya bisa diakses user yang sudah login menggunakan Laravel Sanctum.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Install Sanctum
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require laravel/sanctum
php artisan vendor:publish &lt;span class="nt"&gt;--provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Laravel&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;anctum&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;anctumServiceProvider"&lt;/span&gt;
php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Command ini akan menambahkan tabel &lt;code&gt;personal_access_tokens&lt;/code&gt; yang digunakan untuk menyimpan token API user.&lt;/p&gt;

&lt;p&gt;Tambahkan middleware Sanctum di &lt;code&gt;app/Http/Kernel.php&lt;/code&gt; pada group &lt;code&gt;api&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'api'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'throttle:api'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;\Illuminate\Routing\Middleware\SubstituteBindings&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Setup Model User
&lt;/h2&gt;

&lt;p&gt;Pastikan model &lt;code&gt;User&lt;/code&gt; pakai trait &lt;code&gt;HasApiTokens&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Sanctum\HasApiTokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasApiTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Notifiable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Membuat Endpoint Auth (Login, Register, Logout)
&lt;/h2&gt;

&lt;p&gt;Buat controller misal &lt;code&gt;AuthController&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:controller Api/AuthController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contoh fungsi register, login, dan logout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|email|unique:users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|min:6'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'api-token'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$credentials&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// hapus token lama, 1 user = 1 token aktif&lt;/span&gt;
    &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'api-token'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;plainTextToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;currentAccessToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Logout akan menghapus token aktif sehingga request berikutnya akan ditolak.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Logged out'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Route API Auth &amp;amp; Proteksi Artikel
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;routes/api.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'register'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'register'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth:sanctum'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logout'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AuthController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'logout'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;apiResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ArticleController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5: Testing API Auth dengan Postman
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Register
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/register
Content-Type: application/json
{
  "name": "Atha",
  "email": "atha@mail.com",
  "password": "password123"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Login
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/login
Content-Type: application/json
{
  "email": "atha@mail.com",
  "password": "password123"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Atha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1|longapitoken..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Akses Artikel (dengan token)
&lt;/h3&gt;

&lt;p&gt;Tambahkan header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer 1|longapitoken...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/articles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Error Handling &amp;amp; Status Code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;201 Created: Register sukses&lt;/li&gt;
&lt;li&gt;200 OK: Login sukses, data diambil&lt;/li&gt;
&lt;li&gt;401 Unauthorized: Token salah/expired&lt;/li&gt;
&lt;li&gt;422 Unprocessable Entity: Validasi gagal&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistake Pemula
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lupa publish/migrate Sanctum&lt;/li&gt;
&lt;li&gt;Lupa tambahkan middleware &lt;code&gt;auth:sanctum&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Token tidak dikirim di header&lt;/li&gt;
&lt;li&gt;Lupa set &lt;code&gt;Accept: application/json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Salah endpoint (POST login, bukan GET)&lt;/li&gt;
&lt;li&gt;Salah group route (harus di dalam middleware)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Refresh token&lt;/li&gt;
&lt;li&gt;Role/permission&lt;/li&gt;
&lt;li&gt;API Resource&lt;/li&gt;
&lt;li&gt;Testing dengan Thunder Client&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Yuk Diskusi &amp;amp; Share!
&lt;/h2&gt;

&lt;p&gt;Kalau kamu stuck di step tertentu, tulis di komentar ya! Share juga pengalaman kamu pakai Sanctum, atau request topik lanjutan (refresh token, role, dsb).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Referensi:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs/10.x/sanctum" rel="noopener noreferrer"&gt;Laravel Sanctum Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs/10.x/authentication" rel="noopener noreferrer"&gt;Laravel API Authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>api</category>
      <category>authentication</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Belajar API Laravel: Dari Problem ke Solusi!</title>
      <dc:creator>Muhammad Dhiyaul Atha</dc:creator>
      <pubDate>Sun, 11 Jan 2026 14:24:47 +0000</pubDate>
      <link>https://forem.com/bangkah/belajar-api-laravel-dari-problem-ke-solusi-47p1</link>
      <guid>https://forem.com/bangkah/belajar-api-laravel-dari-problem-ke-solusi-47p1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Pernah nggak, frontend React kamu gagal ambil data dari backend Laravel? Atau Postman cuma muter-muter nggak dapet respon? Tenang, kamu nggak sendirian! Banyak pemula Laravel ngalamin hal yang sama. Di sinilah API Laravel jadi penyelamat."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ketika kamu bikin frontend React dan backend Laravel, tapi data nggak tampil karena API belum siap — itu frustrasi banget. Nah, artikel ini kasih solusi lengkapnya biar kamu nggak pusing lagi!&lt;/p&gt;




&lt;h2&gt;
  
  
  Kenapa API itu Penting?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API itu jembatan antara frontend dan backend&lt;/li&gt;
&lt;li&gt;Wajib untuk Single Page Application (SPA) &amp;amp; mobile app&lt;/li&gt;
&lt;li&gt;Tanpa API, data nggak bisa ditampilkan ke user&lt;/li&gt;
&lt;/ul&gt;







&lt;h2&gt;
  
  
  Contoh API Laravel: CRUD Artikel
&lt;/h2&gt;

&lt;p&gt;Di artikel ini, kita bakal bikin &lt;strong&gt;API Artikel&lt;/strong&gt; (CRUD) pakai Laravel. Simpel, tapi bener-bener kepake buat blog, news, atau project latihan.&lt;/p&gt;




&lt;h2&gt;
  
  
  Alur Kerja API Laravel
&lt;/h2&gt;

&lt;p&gt;Sebelum ngoding, pahami dulu alurnya:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client (Postman / Frontend)
→ Request HTTP
→ Route API
→ Controller
→ Model
→ Database
→ Response JSON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jadi, setiap kali client minta data, request-nya lewat route, diproses controller, ambil data dari model/database, lalu balikin response JSON.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Setup Project Laravel
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Laravel versi terbaru (misal 10.x)&lt;/li&gt;
&lt;li&gt;Pastikan Composer sudah terinstal
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt; laravel/laravel belajar-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting database di &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=belajar_api
DB_USERNAME=root
DB_PASSWORD=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Buat Model &amp;amp; Migration Artikel
&lt;/h2&gt;

&lt;p&gt;Kenapa pakai &lt;code&gt;-m&lt;/code&gt;?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;-m&lt;/code&gt; otomatis bikin migration file, jadi nggak perlu bikin manual.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:model Article &lt;span class="nt"&gt;-m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit migration di &lt;code&gt;database/migrations/..._create_articles_table.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jalankan migrasi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pentingnya &lt;code&gt;$fillable&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Di model &lt;code&gt;Article.php&lt;/code&gt; tambahkan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kenapa harus diisi?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kalau tidak diisi, Laravel tidak bisa menyimpan data karena proteksi mass assignment. Ini fitur keamanan agar data yang masuk ke database benar-benar sesuai yang diizinkan.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 3: Membuat Controller API Artikel
&lt;/h2&gt;

&lt;p&gt;Bikin controller resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:controller Api/ArticleController &lt;span class="nt"&gt;--resource&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Penjelasan fungsi-fungsi utama:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index()&lt;/code&gt; → Ambil semua artikel dari database, balikin dalam bentuk JSON.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;store()&lt;/code&gt; → Simpan artikel baru. Biasanya ambil data dari request, validasi, lalu simpan.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;show($id)&lt;/code&gt; → Ambil detail artikel berdasarkan ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update($id)&lt;/code&gt; → Ubah data artikel tertentu.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;destroy($id)&lt;/code&gt; → Hapus artikel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contoh implementasi (singkat):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Validasi dulu&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'content'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// Simpan data&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$validated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Menambahkan Route API
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;routes/api.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;apiResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Controllers\Api\ArticleController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cara Testing API dengan Postman
&lt;/h2&gt;

&lt;p&gt;Cek endpoint pakai Postman/curl:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Fungsi&lt;/th&gt;
&lt;th&gt;Contoh Request&lt;/th&gt;
&lt;th&gt;Contoh Response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;/api/articles&lt;/td&gt;
&lt;td&gt;List semua artikel&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[ {...} ]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;/api/articles&lt;/td&gt;
&lt;td&gt;Simpan artikel baru&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "title": "Belajar Laravel API", "content": "Tutorial lengkap &amp;amp; mudah!" }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "id": 1, ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Detail artikel&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "id": 1, ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Update artikel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "title": "Update", "content": "Edit konten" }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "id": 1, ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;/api/articles/{id}&lt;/td&gt;
&lt;td&gt;Hapus artikel&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Contoh Lengkap Request &amp;amp; Response
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request POST:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/articles
Content-Type: application/json

{
    "title": "Belajar Laravel API",
    "content": "Tutorial lengkap &amp;amp; mudah!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response 201 Created:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Belajar Laravel API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tutorial lengkap &amp;amp; mudah!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-10"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Request GET:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/articles/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response 200 OK:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Belajar Laravel API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tutorial lengkap &amp;amp; mudah!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-10"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Request PUT:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT /api/articles/1
Content-Type: application/json

{
    "title": "Update Judul",
    "content": "Konten sudah diupdate!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response 200 OK:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Update Judul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Konten sudah diupdate!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-10"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Request DELETE:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETE /api/articles/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response 204 No Content:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Error Handling &amp;amp; Status Code di Laravel
&lt;/h3&gt;

&lt;p&gt;Laravel otomatis mengirim status code sesuai aksi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;200 OK&lt;/strong&gt;: Data berhasil diambil/diupdate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;201 Created&lt;/strong&gt;: Data berhasil dibuat&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;204 No Content&lt;/strong&gt;: Data berhasil dihapus&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;404 Not Found&lt;/strong&gt;: Data tidak ditemukan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;422 Unprocessable Entity&lt;/strong&gt;: Validasi gagal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;500 Internal Server Error&lt;/strong&gt;: Error server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contoh error response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No query results for model [App&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Models&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Article] 99"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tips: Gunakan &lt;code&gt;findOrFail()&lt;/code&gt; untuk otomatis dapat response 404 jika data tidak ditemukan.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistake Pemula
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Kesalahan umum pemula waktu bikin API Laravel:"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Lupa nambah &lt;code&gt;$fillable&lt;/code&gt; di model, jadi data nggak bisa disimpan.&lt;/li&gt;
&lt;li&gt;Pakai method GET buat simpan data (harusnya POST).&lt;/li&gt;
&lt;li&gt;Nggak validasi input, data jadi berantakan.&lt;/li&gt;
&lt;li&gt;Langsung expose semua field tanpa filter.&lt;/li&gt;
&lt;li&gt;Salah setup &lt;code&gt;.env&lt;/code&gt; (database, port, user/password)&lt;/li&gt;
&lt;li&gt;Menjalankan route di &lt;code&gt;web.php&lt;/code&gt; bukan di &lt;code&gt;api.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Lupa restart server setelah ubah konfigurasi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tips:&lt;/strong&gt; Selalu cek error di response, pastikan method &amp;amp; field sudah benar, dan cek konfigurasi environment!&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Step: Level Up API-mu!
&lt;/h2&gt;

&lt;p&gt;Jangan berhenti di CRUD. Coba explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sanctum / Auth&lt;/strong&gt;: Biar API kamu aman&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Resource&lt;/strong&gt;: Format response lebih rapi&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pagination&lt;/strong&gt;: Untuk data banyak&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting&lt;/strong&gt;: Biar nggak di-spam&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tunggu artikel lanjutan ya!&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Yuk Diskusi &amp;amp; Share!
&lt;/h2&gt;

&lt;p&gt;Kalau kamu stuck di step tertentu, tulis di komentar ya! Share juga pengalaman kamu bikin API Laravel, atau request topik lanjutan (autentikasi, API resource, pagination, dll).&lt;/p&gt;

&lt;p&gt;Jangan lupa follow &amp;amp; share artikel ini ke teman yang lagi belajar Laravel!&lt;/p&gt;




&lt;h2&gt;
  
  
  Struktur Ringkas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Masalah yang sering dialami pemula&lt;/li&gt;
&lt;li&gt;Apa yang akan dibuat&lt;/li&gt;
&lt;li&gt;Alur kerja API Laravel&lt;/li&gt;
&lt;li&gt;Setup singkat&lt;/li&gt;
&lt;li&gt;CRUD API step by step&lt;/li&gt;
&lt;li&gt;Testing API&lt;/li&gt;
&lt;li&gt;Kesalahan umum&lt;/li&gt;
&lt;li&gt;Next step / lanjutan&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Referensi:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laravel.com/docs" rel="noopener noreferrer"&gt;Laravel Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
