<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Belajar Teknologi</title>
	<atom:link href="https://ramzilhuda.com/tag/laravel-sanctum/feed/" rel="self" type="application/rss+xml" />
	<link>https://ramzilhuda.com</link>
	<description>Belajar dan Sharing Ilmu Teknologi</description>
	<lastBuildDate>Wed, 14 Oct 2026 09:31:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://i0.wp.com/ramzilhuda.com/wp-content/uploads/2019/09/cropped-thunder.png?fit=32%2C32&#038;ssl=1</url>
	<title>Belajar Teknologi</title>
	<link>https://ramzilhuda.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">166916531</site>	<item>
		<title>Cara Membuat REST API dengan Laravel: Panduan Lengkap untuk Pemula</title>
		<link>https://ramzilhuda.com/cara-membuat-rest-api-laravel/</link>
					<comments>https://ramzilhuda.com/cara-membuat-rest-api-laravel/#respond</comments>
		
		<dc:creator><![CDATA[ramzilhuda]]></dc:creator>
		<pubDate>Wed, 14 Oct 2026 09:31:34 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[api laravel pemula]]></category>
		<category><![CDATA[laravel sanctum]]></category>
		<category><![CDATA[rest api laravel]]></category>
		<category><![CDATA[tutorial laravel]]></category>
		<category><![CDATA[tutorial rest api]]></category>
		<guid isPermaLink="false">https://ramzilhuda.com/?p=1307</guid>

					<description><![CDATA[Setelah aplikasi webmu jadi, pertanyaan berikutnya hampir selalu sama: bagaimana kalau data yang sama perlu dipakai aplikasi mobile, atau ditampilkan di frontend modern seperti Vue dan React? Jawabannya adalah API. Artikel ini membahas cara membuat REST API dengan Laravel secara lengkap, mulai dari endpoint CRUD sampai autentikasi token memakai Laravel Sanctum. Tutorial ini melanjutkan seri [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Setelah <a href="https://ramzilhuda.com/bagaimana-cara-melihata-whatasapp-kita-di-intai-orang-lain/">aplikasi</a> webmu jadi, pertanyaan berikutnya hampir selalu sama: bagaimana kalau data yang sama perlu dipakai aplikasi <a href="https://ramzilhuda.com/tutorial-membuat-aplikasi-quiz-sederhana-menggunakan-android-studio/">mobile</a>, atau ditampilkan di frontend modern seperti Vue dan React? Jawabannya adalah API. Artikel ini membahas cara membuat REST API dengan <a href="https://ramzilhuda.com/cara-membuat-project-sederhana-menggunakan-laravel-part-1/">Laravel</a> secara lengkap, mulai dari endpoint CRUD sampai autentikasi token memakai Laravel Sanctum.</p>
<p>Tutorial ini melanjutkan seri Laravel di blog ini. Kita akan memakai contoh yang sama dengan tutorial sebelumnya, yaitu data produk dengan kolom name, description, price, dan stock. Bedanya, kali ini datanya tidak ditampilkan lewat Blade, melainkan disajikan sebagai data JSON yang bisa dikonsumsi aplikasi apa pun. Kalau kamu belum mengikuti tutorial CRUD sebelumnya, sangat disarankan menyelesaikannya dulu agar <a href="https://ramzilhuda.com/tujuan-mengevaluasi-model-artificial-neural-network-dengan-cross-validation/">model</a> dan tabel produknya sudah siap.</p>
<p><img data-recalc-dims="1" decoding="async" alt="Alur request REST API Laravel dari client ke database" src="https://i0.wp.com/ramzilhuda.com/wp-content/uploads/2026/10/media-generation-rest-api-laravel-diagram.webp?ssl=1" /></p>
<h2>Apa Itu REST API dan Kenapa Laravel Cocok untuk Itu</h2>
<p>REST API adalah cara standar dua aplikasi berkomunikasi lewat HTTP. Client mengirim request ke sebuah alamat (endpoint), lalu server membalas dengan data, biasanya dalam format JSON. Setiap operasi memakai method HTTP yang berbeda, dan pola ini berlaku konsisten di hampir semua API modern.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Endpoint contoh</th>
<th>Fungsi</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td>/api/products</td>
<td>Mengambil semua data produk</td>
</tr>
<tr>
<td>GET</td>
<td>/api/products/1</td>
<td>Mengambil satu produk berdasarkan ID</td>
</tr>
<tr>
<td>POST</td>
<td>/api/products</td>
<td>Menambah produk baru</td>
</tr>
<tr>
<td>PUT atau PATCH</td>
<td>/api/products/1</td>
<td>Mengubah produk berdasarkan ID</td>
</tr>
<tr>
<td>DELETE</td>
<td>/api/products/1</td>
<td>Menghapus produk berdasarkan ID</td>
</tr>
</tbody>
</table>
<p>Laravel cocok untuk membuat REST API karena tiga alasan. Pertama, routing dan resource controller-nya memang dirancang mengikuti pola REST. Kedua, Eloquent membuat urusan database menjadi singkat. Ketiga, ekosistemnya lengkap: ada Sanctum untuk autentikasi token, API Resource untuk mengatur format JSON, dan validasi bawaan yang rapi. Kamu tidak perlu memasang banyak paket tambahan hanya untuk membuat API yang layak pakai.</p>
<h2>Prasyarat Sebelum Mulai</h2>
<p>Pastikan hal berikut sudah siap di komputermu:</p>
<ol>
<li>Proyek Laravel 12 dari tutorial CRUD sebelumnya, dengan model Product dan tabel products yang sudah termigrasi.</li>
<li>Server lokal berjalan lewat perintah php artisan serve.</li>
<li>Aplikasi untuk menguji API, misalnya Postman, Insomnia, atau cukup terminal untuk perintah curl.</li>
</ol>
<p>Kalau proyek CRUD belum ada, kamu tetap bisa mengikuti tutorial ini dari proyek Laravel baru. Cukup buat model dan migration produk seperti pada tutorial sebelumnya, lalu lanjutkan dari langkah pertama di bawah.</p>
<h2>Langkah 1: Memasang Sanctum dengan Perintah install:api</h2>
<p>Di Laravel versi modern, dukungan API tidak aktif secara bawaan agar proyek web biasa tetap ringan. Untuk mengaktifkannya, jalankan satu perintah berikut di terminal proyekmu:</p>
<pre><code class="language-bash">php artisan install:api
</code></pre>
<p>Perintah ini melakukan beberapa hal sekaligus: memasang paket Laravel Sanctum, membuat file routes/api.php, dan menyiapkan migration untuk tabel personal_access_tokens yang nanti menyimpan token login pengguna. Setelah perintah selesai, jalankan migration:</p>
<pre><code class="language-bash">php artisan migrate
</code></pre>
<p>Semua route yang kamu tulis di routes/api.php otomatis memakai awalan /api. Jadi route products di file itu akan diakses sebagai /api/products. Inilah yang membedakannya dari route web di routes/web.php.</p>
<h2>Langkah 2: Membuat Controller Khusus API</h2>
<p>Jangan mencampur controller web dan controller API dalam satu file. Controller web mengembalikan tampilan Blade, sedangkan controller API mengembalikan JSON. Buat controller baru di dalam folder Api:</p>
<pre><code class="language-bash">php artisan make:controller Api/ProductController
</code></pre>
<p>Buka file app/Http/Controllers/Api/ProductController.php, lalu isi dengan kode berikut:</p>
<pre><code class="language-php">&lt;?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index()
    {
        return ProductResource::collection(Product::latest()-&gt;paginate(10));
    }

    public function store(Request $request)
    {
        $validated = $request-&gt;validate([
            'name' =&gt; 'required|string|max:255',
            'description' =&gt; 'nullable|string',
            'price' =&gt; 'required|numeric|min:0',
            'stock' =&gt; 'required|integer|min:0',
        ]);

        $product = Product::create($validated);

        return (new ProductResource($product))
            -&gt;response()
            -&gt;setStatusCode(201);
    }

    public function show(Product $product)
    {
        return new ProductResource($product);
    }

    public function update(Request $request, Product $product)
    {
        $validated = $request-&gt;validate([
            'name' =&gt; 'sometimes|string|max:255',
            'description' =&gt; 'nullable|string',
            'price' =&gt; 'sometimes|numeric|min:0',
            'stock' =&gt; 'sometimes|integer|min:0',
        ]);

        $product-&gt;update($validated);

        return new ProductResource($product);
    }

    public function destroy(Product $product)
    {
        $product-&gt;delete();

        return response()-&gt;json(['message' =&gt; 'Produk berhasil dihapus.']);
    }
}
</code></pre>
<p>Ada tiga hal yang perlu diperhatikan dari kode di atas. Pertama, validasi tetap dilakukan di setiap operasi tulis, sama seperti CRUD versi web. Kedua, pada method update kita memakai aturan sometimes agar client boleh mengubah sebagian kolom saja, sesuai sifat method PATCH. Ketiga, method show dan update memakai route model binding: Laravel otomatis mencari produk berdasarkan ID di URL, dan otomatis membalas 404 bila ID tidak ditemukan. Kamu tidak perlu menulis pencarian manual.</p>
<p>Sebagai pengembangan lanjutan, validasi di controller ini nantinya bisa dipisah ke Form Request agar controller lebih ramping. Untuk tahap dasar, validasi langsung seperti ini sudah cukup dan lebih mudah diikuti.</p>
<h2>Langkah 3: Mengatur Format JSON dengan API Resource</h2>
<p>Kalau model langsung dikembalikan sebagai JSON, semua kolom di tabel akan ikut tampil, termasuk yang seharusnya tidak perlu diketahui client. API Resource memberi kamu kendali penuh atas kolom apa saja yang dikirim. Buat resource-nya:</p>
<pre><code class="language-bash">php artisan make:resource ProductResource
</code></pre>
<p>Lalu buka app/Http/Resources/ProductResource.php dan ubah method toArray menjadi:</p>
<pre><code class="language-php">public function toArray(Request $request): array
{
    return [
        'id' =&gt; $this-&gt;id,
        'name' =&gt; $this-&gt;name,
        'description' =&gt; $this-&gt;description,
        'price' =&gt; (int) $this-&gt;price,
        'stock' =&gt; (int) $this-&gt;stock,
        'created_at' =&gt; $this-&gt;created_at?-&gt;toDateTimeString(),
        'updated_at' =&gt; $this-&gt;updated_at?-&gt;toDateTimeString(),
    ];
}
</code></pre>
<p>Jangan lupa menambahkan use Illuminate\Http\Request; di bagian atas file bila belum ada. Dengan resource ini, format balasan akan konsisten di semua endpoint: data produk dibungkus dalam kunci data, dan untuk daftar produk Laravel otomatis menambahkan informasi pagination seperti total halaman. Konsistensi format seperti ini yang membuat API nyaman dipakai tim frontend.</p>
<h2>Langkah 4: Mendaftarkan Route API</h2>
<p>Sekarang daftarkan endpoint-nya di routes/api.php:</p>
<pre><code class="language-php">&lt;?php

use App\Http\Controllers\Api\ProductController;
use Illuminate\Support\Facades\Route;

Route::apiResource('products', ProductController::class);
</code></pre>
<p>Satu baris apiResource itu menghasilkan lima endpoint sekaligus sesuai tabel di awal artikel. Untuk memastikan semuanya terdaftar dengan benar, jalankan:</p>
<pre><code class="language-bash">php artisan route:list --path=api
</code></pre>
<p>Kamu akan melihat daftar route beserta method HTTP dan controller tujuannya. Bila daftar ini sudah muncul, API dasarmu sebenarnya sudah jadi dan siap diuji.</p>
<h2>Langkah 5: Menguji API dengan curl</h2>
<p>Pastikan server berjalan, lalu buka terminal baru dan coba beberapa perintah berikut.</p>
<p>Mengambil semua produk:</p>
<pre><code class="language-bash">curl http://127.0.0.1:8000/api/products
</code></pre>
<p>Menambah produk baru:</p>
<pre><code class="language-bash">curl -X POST http://127.0.0.1:8000/api/products -H &quot;Content-Type: application/json&quot; -H &quot;Accept: application/json&quot; -d '{&quot;name&quot;:&quot;Keyboard Mechanical&quot;,&quot;description&quot;:&quot;Keyboard RGB hot swap&quot;,&quot;price&quot;:350000,&quot;stock&quot;:12}'
</code></pre>
<p>Balasan yang benar untuk penambahan data adalah status 201 Created beserta data produk yang baru dibuat, lengkap dengan ID-nya. Kalau kamu mendapat status 422, berarti validasi gagal dan pesan errornya ada di dalam JSON balasan. Baca pesan itu baik baik, karena di situlah petunjuk kolom mana yang bermasalah.</p>
<p>Di Postman, langkahnya setara: pilih method POST, masukkan URL yang sama, buka tab Body, pilih raw dan JSON, lalu tempel isi data produknya. Jangan lupa selalu mengirim header Accept: application/json agar Laravel membalas error dalam format JSON, bukan halaman HTML.</p>
<h2>Langkah 6: Menambahkan Autentikasi Token dengan Sanctum</h2>
<p>API yang terbuka untuk siapa pun cocok untuk data publik, tetapi operasi tambah, ubah, dan hapus data sebaiknya hanya boleh dilakukan pengguna yang sudah login. Sanctum menyelesaikan ini dengan token: pengguna login sekali, menerima token, lalu mengirim token itu di setiap request berikutnya.</p>
<p>Pertama, aktifkan trait HasApiTokens pada model User. Buka app/Models/User.php dan sesuaikan bagian atas class:</p>
<pre><code class="language-php">use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    // ...
}
</code></pre>
<p>Kedua, buat controller autentikasi:</p>
<pre><code class="language-bash">php artisan make:controller Api/AuthController
</code></pre>
<p>Isi file app/Http/Controllers/Api/AuthController.php dengan kode berikut:</p>
<pre><code class="language-php">&lt;?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validated = $request-&gt;validate([
            'name' =&gt; 'required|string|max:255',
            'email' =&gt; 'required|string|email|unique:users',
            'password' =&gt; 'required|string|min:8|confirmed',
        ]);

        $user = User::create([
            'name' =&gt; $validated['name'],
            'email' =&gt; $validated['email'],
            'password' =&gt; Hash::make($validated['password']),
        ]);

        return response()-&gt;json([
            'user' =&gt; $user,
            'token' =&gt; $user-&gt;createToken('api-token')-&gt;plainTextToken,
        ], 201);
    }

    public function login(Request $request)
    {
        $request-&gt;validate([
            'email' =&gt; 'required|string|email',
            'password' =&gt; 'required|string',
        ]);

        $user = User::where('email', $request-&gt;email)-&gt;first();

        if (! $user || ! Hash::check($request-&gt;password, $user-&gt;password)) {
            throw ValidationException::withMessages([
                'email' =&gt; ['Email atau password salah.'],
            ]);
        }

        return response()-&gt;json([
            'user' =&gt; $user,
            'token' =&gt; $user-&gt;createToken('api-token')-&gt;plainTextToken,
        ]);
    }

    public function logout(Request $request)
    {
        $request-&gt;user()-&gt;currentAccessToken()-&gt;delete();

        return response()-&gt;json(['message' =&gt; 'Berhasil logout.']);
    }
}
</code></pre>
<p>Ketiga, perbarui routes/api.php agar endpoint produk terlindungi, sedangkan register dan login tetap terbuka:</p>
<pre><code class="language-php">&lt;?php

use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\ProductController;
use Illuminate\Support\Facades\Route;

Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

Route::middleware('auth:sanctum')-&gt;group(function () {
    Route::apiResource('products', ProductController::class);
    Route::post('/logout', [AuthController::class, 'logout']);
});
</code></pre>
<p>Pola ini umum dipakai: membaca data pun bisa kamu longgarkan bila memang datanya publik, misalnya memindahkan method index dan show ke luar grup middleware. Untuk latihan ini, semua endpoint produk kita lindungi agar perilaku tokennya terlihat jelas.</p>
<h2>Langkah 7: Menguji Endpoint yang Terlindungi</h2>
<p>Coba akses /api/products tanpa token. Laravel akan membalas status 401 Unauthorized. Itu tanda perlindungannya bekerja.</p>
<p>Selanjutnya login untuk mendapatkan token:</p>
<pre><code class="language-bash">curl -X POST http://127.0.0.1:8000/api/login -H &quot;Content-Type: application/json&quot; -H &quot;Accept: application/json&quot; -d '{&quot;email&quot;:&quot;contoh@mail.com&quot;,&quot;password&quot;:&quot;password123&quot;}'
</code></pre>
<p>Salin nilai token dari balasan, lalu pakai pada request berikutnya lewat header Authorization:</p>
<pre><code class="language-bash">curl http://127.0.0.1:8000/api/products -H &quot;Accept: application/json&quot; -H &quot;Authorization: Bearer TOKEN_KAMU&quot;
</code></pre>
<p>Kali ini data produk akan tampil. Di Postman, token yang sama bisa diisi pada tab Authorization dengan tipe Bearer Token. Simpan token ini baik baik dan jangan pernah menaruhnya di kode frontend yang dipublikasikan, karena siapa pun yang memiliki token itu bisa bertindak atas nama pengguna pemiliknya.</p>
<h2>Troubleshooting yang Sering Terjadi</h2>
<p><strong>Route /api tidak ditemukan (404).</strong> Biasanya karena install:api belum dijalankan atau file routes/api.php belum terdaftar. Jalankan php artisan route:list &#8211;path=api untuk memastikan, dan bersihkan cache route dengan php artisan route:clear bila perlu.</p>
<p><strong>Balasan error berupa halaman HTML, bukan JSON.</strong> Client tidak mengirim header Accept: application/json. Tambahkan header itu di curl atau Postman, terutama saat menguji validasi dan autentikasi.</p>
<p><strong>Status 401 padahal sudah login.</strong> Periksa tiga hal: token disalin utuh tanpa spasi tambahan, header diawali kata Bearer diikuti satu spasi, dan route memang berada di dalam grup auth:sanctum. Kesalahan paling sering adalah token tertukar dengan token dari sesi login lama yang sudah dihapus.</p>
<p><strong>Class HasApiTokens tidak ditemukan.</strong> Artinya Sanctum belum terpasang. Jalankan kembali php artisan install:api, atau pasang manual dengan composer require laravel/sanctum lalu php artisan vendor:publish untuk konfigurasinya.</p>
<p><strong>Error kolom tidak boleh diisi (mass assignment).</strong> Sama seperti tutorial CRUD: pastikan semua kolom produk sudah terdaftar di properti fillable pada model Product.</p>
<h2>FAQ REST API Laravel</h2>
<p><strong>1. Apa bedanya Route::apiResource dan Route::resource?</strong><br />
apiResource hanya membuat lima route untuk operasi data (index, store, show, update, destroy), sedangkan resource menambahkan route create dan edit yang dipakai untuk menampilkan form HTML. Karena API tidak punya form, apiResource adalah pilihan yang tepat.</p>
<p><strong>2. Apakah REST API Laravel harus selalu memakai Sanctum?</strong><br />
Tidak selalu. API publik yang hanya menampilkan data terbuka bisa dibuat tanpa autentikasi. Sanctum dipakai bila ada data milik pengguna atau operasi tulis yang perlu dibatasi. Untuk komunikasi antar server yang lebih kompleks, ada juga Laravel Passport berbasis OAuth2, tetapi untuk kebanyakan aplikasi pemula Sanctum jauh lebih sederhana.</p>
<p><strong>3. Bagaimana cara membatasi jumlah data per halaman?</strong><br />
Pada contoh ini kita memakai paginate(10), dan client bisa berpindah halaman dengan menambahkan ?page=2 pada URL. Jumlah per halaman boleh diubah sesuai kebutuhan, dan lazimnya disertakan juga pilihan per_page dari query string bila API dipakai banyak client.</p>
<p><strong>4. Bisakah API ini dipakai aplikasi <a href="https://ramzilhuda.com/tutorial-pengenalan-framework-flutter/">Flutter</a> atau React Native?</strong><br />
Bisa, dan memang untuk itulah API ini dibuat. Aplikasi mobile cukup mengirim request HTTP ke endpoint yang sama dan membaca balasan JSON-nya. Yang perlu diperhatikan, alamat 127.0.0.1 hanya berlaku di komputer pengembang. Untuk pengujian dari HP, gunakan alamat IP lokal komputer atau layanan tunnel selama pengembangan.</p>
<p><strong>5. Bagaimana cara membuat versi API, misalnya v1 dan v2?</strong><br />
Kelompokkan route ke dalam awalan versi, contohnya Route::prefix(&#8216;v1&#8217;) pada grup route, sehingga URL menjadi /api/v1/products. Dengan cara ini, perubahan besar di masa depan bisa diterbitkan sebagai v2 tanpa merusak aplikasi lama yang masih memakai v1.</p>
<h2>Kesimpulan</h2>
<p>Kamu baru saja mengubah aplikasi CRUD Laravel menjadi REST API yang utuh: endpoint produk dengan format JSON yang konsisten lewat API Resource, validasi di setiap operasi tulis, pagination, dan autentikasi token memakai Sanctum. Pola ini adalah fondasi hampir semua <a href="https://ramzilhuda.com/mengenal-server-peran-dan-tipe-server-yang-perlu-diketahui/">backend</a> modern, baik untuk aplikasi mobile, frontend JavaScript, maupun <a href="https://ramzilhuda.com/metode-numerik-integrasi-numerik/">integrasi</a> antar layanan.</p>
<p>Langkah alami berikutnya adalah menerapkan pola yang sama ke data lain di aplikasimu, lalu mempelajari cara men-deploy API ini ke server agar bisa diakses dari mana saja. Sebagai penguat dasar, baca kembali seri awalnya di <a href="https://ramzilhuda.com/tutorial-laravel-12-crud-pemula/">Tutorial Laravel 12: Membuat CRUD Sederhana dari Nol untuk Pemula</a> dan padukan dengan bantuan <a href="https://ramzilhuda.com/ai-membantu-penemuan-obat-chatbot-dan-pencarian-yang-revolusioner/">AI</a> secara etis lewat panduan <a href="https://ramzilhuda.com/tools-ai-gratis-untuk-mahasiswa/">5 Tools AI Gratis untuk Mahasiswa</a> yang juga sudah terbit di blog ini.</p>
<p><em>Sudah berhasil membuat endpoint pertamamu? Ceritakan di kolom komentar method mana yang paling membingungkan, nanti kita bahas bersama.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://ramzilhuda.com/cara-membuat-rest-api-laravel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1307</post-id>	</item>
	</channel>
</rss>
