Belajar Laravel - API Development (REST)
Episode 17 of 24

Belajar Laravel - API Development (REST)

Membangun REST API di Laravel: route api.php, API Resources sebagai transformer, JSON responses yang konsisten, versioning, pagination, dan dokumentasi API dengan Scribe.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Saat ini hampir semua aplikasi punya sisi API — untuk mobile app, frontend SPA, integrasi pihak ketiga, atau sekadar memisahkan logika dari tampilan. Di episode ini kita bangun REST API di Laravel dengan pola yang benar: struktur response yang konsisten, resource transformer, pagination, dan dokumentasi.

Prinsip penting yang membedakan API yang baik: konsistensi. JSON yang terstruktur seragam membuat client mudah memakainya — dan dokumentasi yang jelas membuat tim lain tidak perlu membaca source code.

Route API: routes/api.php

API memakai file routes/api.php yang prefix-nya /api:

routes/api.php
Route::get('/posts', [Api\PostController::class, 'index']);
Route::get('/posts/{post}', [Api\PostController::class, 'show']);
Route::post('/posts', [Api\PostController::class, 'store'])
    ->middleware('auth:sanctum');

Route di api.php otomatis diawali /api (diatur di RouteServiceProvider/bootstrap). Perhatikan perbedaannya dengan web.php: tanpa session & CSRF, memakai guard sanctum untuk autentikasi (episode 18). Cek dengan:

Lihat route API
php artisan route:list --path=api

Controller API dan JSON Responses

Buat controller khusus API:

Buat API controller
php artisan make:controller Api/PostController --api
app/Http/Controllers/Api/PostController.php
<?php
 
namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
    public function index()
    {
        return PostResource::collection(
            Post::query()
                ->where('status', 'published')
                ->paginate(15)
        );
    }
 
    public function show(Post $post)
    {
        return new PostResource($post);
    }
 
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'body'  => 'required|string',
        ]);
 
        $post = $request->user()->posts()->create($validated);
 
        return (new PostResource($post))
            ->response()
            ->setStatusCode(201);
    }
}

Mengembalikan resource secara langsung membuat Laravel menghasilkan JSON dengan status code yang sesuai — 200 untuk koleksi/detail, 201 untuk resource yang baru dibuat.

API Resource: Transformer Response

API Resource mengontrol bentuk JSON — kolom apa saja yang boleh keluar, dan bagaimana formatnya:

Buat resource
php artisan make:resource PostResource
app/Http/Resources/PostResource.php
<?php
 
namespace App\Http\Resources;
 
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
 
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'title'      => $this->title,
            'slug'       => $this->slug,
            'excerpt'    => str($this->body)->limit(160),
            'created_at' => $this->created_at->toIso8601String(),
            'author'     => new UserResource($this->whenLoaded('author')),
        ];
    }
}

Keuntungannya: kalian bisa menyembunyikan kolom sensitif (user_id internal, dsb.), menambahkan field turunan, dan menampilkan relasi hanya jika sudah di-eager load (whenLoaded). Client melihat API yang bersih, terlepas dari struktur tabel internal.

Respons API yang Konsisten

Untuk keseragaman error API, bungkus di helper atau gunakan pola:

Struktur error yang konsisten
return response()->json([
    'message' => 'The given data was invalid.',
    'errors'  => $validator->errors(),
], 422);

Konsisten = client tahu persis apa yang harus diparsing. Satu struktur untuk sukses, satu untuk error, satu untuk validasi.

Pagination di API

paginate(15) pada koleksi resource menghasilkan struktur pagination otomatis:

json
{
  "data": [ ... ],
  "links": {
    "first": "...",
    "last": "...",
    "prev": null,
    "next": "..."
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 7,
    "path": "...",
    "per_page": 15,
    "to": 15,
    "total": 97
  }
}

Client memakai links.next untuk mengambil halaman berikutnya — tidak perlu parsing URL manual.

Versioning API

API berubah seiring waktu; client lama harus tetap jalan. Versioning adalah cara mengelola perubahan itu:

Versioning via prefix
Route::prefix('v1')->group(function () {
    Route::get('/posts', [Api\V1\PostController::class, 'index']);
});
 
Route::prefix('v2')->group(function () {
    Route::get('/posts', [Api\V2\PostController::class, 'index']);
});

Dengan URL /api/v1/posts dan /api/v2/posts, versi lama bisa di-deprecate bertahap tanpa memutus client lama. Aturan praktis: tambahkan versi baru ketika ada breaking change pada struktur response.

Dokumentasi API dengan Scribe

Dokumentasi yang hidup selalu up-to-date dengan kode. Scribe menghasilkan dokumentasi API interaktif dari atribut route dan controller:

Install Scribe
composer require --dev knuckleswtf/scribe
php artisan scribe:install

Anotasi di controller menjadi dokumentasi:

Anotasi Scribe
/**
 * Daftar post yang sudah dipublikasikan.
 *
 * @queryParam page int Nomor halaman.
 * @queryParam search string Filter judul.
 */
public function index()
{
    // ...
}
Generate dokumentasi
php artisan scribe:generate

Alternatif lain yang umum adalah L5 Swagger (OpenAPI). Mana pun yang dipakai, dokumentasi otomatis lebih baik daripada dokumen yang ditulis tangan dan cepat basi.

Penutup

Inti yang harus dibawa pulang:

  • Route API di routes/api.php (prefix /api), tanpa session/CSRF.
  • Controller API mengembalikan Resource — JSON yang konsisten dan terkontrol.
  • API Resources adalah transformer: sembunyikan kolom sensitif, format relasi via whenLoaded.
  • paginate() menghasilkan struktur links/meta siap pakai untuk client.
  • Version API (/api/v1, /api/v2) dan dokumentasikan dengan Scribe.

Di episode 18 selanjutnya kita akan membahas API authentication dengan Sanctum — API tokens, HasApiTokens, authorization Bearer, token abilities/scope, dan perbandingan Sanctum vs Passport (OAuth). Sampai jumpa di episode 18!

Belajar Laravel - API Development (REST) | Belajar Laravel