Bangun backend sederhana untuk Toko Kue-mu! Pelajari cara membuat API Routes (Route Handlers) di Next.js App Router untuk mengambil semua produk dan detail produk dari data dummy JSON.
Bikin "Dapur" Data Toko Kue: API Routes Pake Next.js!
Udah punya "resep" (interface Kue) dan "bahan baku" (daftar-kue.json) buat Toko Kue kita? Mantap! Sekarang, gimana caranya biar "etalase" (frontend React) kita bisa ngambil data kue itu buat ditampilin ke pengunjung?
Kita gak bakal langsung ngimpor file JSON itu ke komponen frontend kita (meskipun bisa buat kasus super simpel). Cara yang lebih "profesional" dan fleksibel, apalagi kalau nanti datanya dateng dari database beneran, adalah dengan bikin API Endpoint sendiri di dalam proyek Next.js kita. Jadi, frontend kita bakal "minta" data kue ke API internal ini.
Di Next.js App Router, cara bikin API endpoint ini adalah pake Route Handlers.
Apa Itu Route Handlers di Next.js App Router?
Route Handlers ngebolehin kamu bikin endpoint API kustom yang bisa nanganin HTTP request (kayak GET, POST, PUT, DELETE, dll.) dan ngasih HTTP response. Ini semua dilakuin di sisi server.
Cara Bikin: Kamu bikin file bernama route.ts (atau .js) di dalam folder di direktori app/. Nama folder itu yang bakal jadi path API endpoint-nya.
Fungsi Ekspor: Di dalam route.ts itu, kamu ngekspor fungsi-fungsi asinkron yang namanya sesuai sama HTTP method yang mau kamu tangani (huruf besar semua): GET, POST, PUT, PATCH, DELETE.
Request & Response: Fungsi-fungsi ini bisa nerima objek Request (mirip Web API standar) dan harus ngembaliin objek Response (atau NextResponse dari next/server buat kemudahan).
Langkah 1: Bikin API Route buat Ngambil SEMUA Produk Kue
Kita mau bikin endpoint /api/kue yang kalau di-GET, bakal ngasih semua data kue dari daftar-kue.json kita.
Bikin Struktur Folder:
Di dalam src/app/, bikin folder api.
Di dalam src/app/api/, bikin lagi folder kue.
Strukturnya jadi: src/app/api/kue/
Bikin File route.ts:
Di dalam folder src/app/api/kue/, bikin file baru bernama route.ts.
File src/app/api/kue/route.ts:
typescript
// src/app/api/kue/route.tsimport { NextResponse } from 'next/server';import kueLengkap from '@/data/daftar-kue.json'; // Impor data dummy kita// Pastikan path ke daftar-kue.json sudah benar. // Jika kue.ts (interface) dan daftar-kue.json ada di src/data/// dan API route ini ada di src/app/api/kue/, maka pathnya bisa jadi:// import kueLengkap from '../../../../data/daftar-kue.json'; // Atau, jika kamu setup path alias di tsconfig.json (misal '@/' ke 'src/'), // bisa jadi lebih rapi: import kueLengkap from '@/data/daftar-kue.json';// Untuk contoh ini, saya asumsikan kamu sudah setup alias `@/` ke `src/` di tsconfig.json// atau kamu sesuaikan path impornya.// Impor tipe Kue jika perlu untuk validasi atau anotasi (opsional di sini)// import { Kue } from '@/types/kue'; export async function GET(request: Request) { // Di sini kita gak perlu ngapa-ngapain request-nya karena mau ngambil semua // Langsung kembalikan semua data kue sebagai JSON // Kita bisa asumsikan kueLengkap sudah sesuai tipe Kue[] jika diimpor dari file .ts // atau kita bisa lakukan validasi sederhana jika ini dari sumber eksternal. // Untuk data dummy JSON, kita langsung kirim. return NextResponse.json(kueLengkap);}// Kamu juga bisa nambahin handler buat method lain (POST, dll.) di sini kalau perlu// export async function POST(request: Request) { ... }
Penjelasan:
import { NextResponse } from 'next/server';: NextResponse itu helper dari Next.js buat bikin objek Response HTTP dengan gampang, terutama buat ngirim JSON.
import kueLengkap from '@/data/daftar-kue.json';: Kita impor data dummy kue kita.
PENTING SOAL PATH ALIAS @/: Kalau kamu mau pake alias @/ yang nunjuk ke folder src/ (biar path impor lebih pendek), kamu perlu pastiin itu udah dikonfigurasi di file tsconfig.json-mu. Pas create-next-app dengan src/ directory, ini biasanya udah otomatis ada atau gampang ditambahin:
jsonc
// tsconfig.json{ "compilerOptions": { // ... "baseUrl": ".", // Atau "./src" jika semua path @/ relatif ke src "paths": { "@/*": ["./src/*"] // Atau "/*" jika baseUrl adalah "./src" } // ... }}
Kalau gak mau pake alias, ganti path impornya jadi path relatif yang bener (misal, ../../../../data/daftar-kue.json dari src/app/api/kue/).
export async function GET(request: Request): Kita bikin fungsi GET yang diekspor. Fungsi ini bakal otomatis dijalanin sama Next.js kalau ada HTTP GET request ke /api/kue. Parameter request itu objek Request standar Web API.
return NextResponse.json(kueLengkap);: Kita langsung ngembaliin semua data kueLengkap sebagai response JSON. NextResponse.json() otomatis ngeset header Content-Type: application/json dan ngasih status code 200 OK.
Tes API Endpoint-nya!
Jalanin development server-mu (npm run dev).
Buka browser atau Postman, terus akses URL: http://localhost:3000/api/kue
Harusnya kamu liat semua data kue dari daftar-kue.json tampil sebagai JSON!
Langkah 2: Bikin API Route buat Ngambil SATU Produk Kue Berdasarkan ID
Sekarang, kita mau bikin endpoint /api/kue/[id] yang kalau di-GET (dengan [id] diganti ID kue tertentu), bakal ngasih detail kue itu aja. Ini pake Dynamic Route Segment di API Routes.
Bikin Struktur Folder Dinamis:
Di dalam src/app/api/kue/, bikin folder baru yang namanya [id] (iya, pake kurung siku).
Strukturnya jadi: src/app/api/kue/[id]/
Bikin File route.ts di dalam Folder Dinamis:
Di dalam folder src/app/api/kue/[id]/, bikin file baru bernama route.ts.
File src/app/api/kue/[id]/route.ts:
typescript
// src/app/api/kue/[id]/route.tsimport { NextResponse } from 'next/server';import kueLengkap from '@/data/daftar-kue.json';import { Kue } from '@/types/kue'; // Impor tipe Kueinterface RouteParams { params: { id: string; // Nama parameter 'id' harus sama kayak nama folder dinamis '[id]' }}export async function GET(request: Request, { params }: RouteParams) { // Ingat, di Next.js 15+, akses ke params di Route Handlers juga bisa jadi asynchronous // jika Next.js mendeteksinya sebagai 'dynamic' (tergantung bagaimana ia dipanggil atau dikonfigurasi). // Namun, untuk Route Handlers, parameter kedua biasanya langsung berisi objek params yang sudah di-resolve. // Kita akan asumsikan `params` sudah di-resolve di sini untuk kesederhanaan contoh dasar. // Jika ada warning atau error terkait Promise, kita bisa `await params;` const kueId = params.id; // Ambil ID kue dari parameter URL const kueDitemukan = (kueLengkap as Kue[]).find(kue => kue.id === kueId); if (kueDitemukan) { return NextResponse.json(kueDitemukan); } else { // Kalau kue gak ditemuin, kasih response 404 Not Found return NextResponse.json({ message: `Kue dengan ID "${kueId}" tidak ditemukan.` }, { status: 404 }); }}
Penjelasan:
interface RouteParams { params: { id: string; } }: Kita definisiin tipe buat parameter kedua fungsi GET. Next.js bakal ngasih objek yang punya properti params, dan di dalam params itu ada properti yang namanya sama kayak nama folder dinamis kita (id).
const kueId = params.id;: Kita ambil nilai id dari URL.
(kueLengkap as Kue[]).find(...): Kita cari kue di kueLengkap yang id-nya cocok. Kita pake type assertion as Kue[] biar TypeScript tau kueLengkap itu array dari Kue dan kita bisa pake metode find dengan aman dan properti kue.id.
Kalau ketemu, kita kirim data kuenya.
Kalau gak ketemu, kita kirim response JSON dengan pesan error dan status code 404.
Tes API Endpoint Dinamisnya!
Pastikan dev server jalan.
Coba akses di browser atau Postman:
http://localhost:3000/api/kue/kue-coklat-klasik-01 (Harusnya nampilin data Kue Coklat Klasik).
http://localhost:3000/api/kue/roti-tawar-gandum-02 (Harusnya nampilin data Roti Tawar Gandum).
Seperti yang kita bahas dari update Next.js 15, fungsi GET di Route Handlers tidak dicache secara default. Ini berarti setiap request ke API kita akan selalu menjalankan logika fungsinya.
Kalau data kue kita ini sifatnya statis (gak sering berubah), kita bisa mengaktifkan caching biar responsenya lebih cepet dan ngurangin beban server (meskipun server kita cuma baca file JSON sekarang 😉).
Caranya, tambahin export const dynamic = 'force-static'; di file route.ts-nya:
File src/app/api/kue/route.ts (Contoh dengan Caching):
typescript
import { NextResponse } from 'next/server';import kueLengkap from '@/data/daftar-kue.json';// Membuat Next.js mencoba men-cache hasil dari GET request ini saat build (SSG)// atau saat request pertama (ISR-like behavior)export const dynamic = 'force-static';// Opsi lain: 'auto' (default, dinamis), 'error' (error jika dinamis), 'force-dynamic'export async function GET(request: Request) { return NextResponse.json(kueLengkap);}
Lakukan hal yang sama untuk src/app/api/kue/[id]/route.ts jika kamu mau endpoint detail produk juga di-cache.
Ini akan membuat Next.js mencoba men-generate response untuk API ini saat proses build (jika memungkinkan) atau men-cache hasilnya setelah request pertama, jadi request berikutnya bisa dilayani lebih cepat dari cache.
Selamat! Kamu baru aja bikin "dapur" atau backend mini buat Toko Kue-mu pake API Routes (Route Handlers) di Next.js! Kita udah punya dua endpoint: satu buat ngambil semua data kue, satu lagi buat ngambil detail kue spesifik.
Ini fondasi data yang penting banget. Di bagian selanjutnya, kita bakal mulai "ngedekor etalase"-nya, yaitu ngebangun halaman frontend buat nampilin daftar produk kue ini pake Server Component dan fetch ke API yang baru aja kita buat.