Pelajari cara membuat titik akhir API yang andal menggunakan Route Handler Next.js. Panduan ini mencakup semua, mulai dari penyiapan dasar hingga teknik tingkat lanjut, dengan contoh praktis dan praktik terbaik.
Route Handler Next.js: Panduan Komprehensif untuk Membuat Titik Akhir API
Next.js telah merevolusi cara kita membangun aplikasi web dengan fitur-fitur andalannya seperti server-side rendering, static site generation, dan kini, Route Handler. Route Handler menyediakan cara yang fleksibel dan efisien untuk membuat titik akhir API langsung di dalam aplikasi Next.js Anda. Panduan ini akan menjelajahi konsep Route Handler, manfaatnya, dan cara menggunakannya secara efektif untuk membangun API yang tangguh.
Apa itu Route Handler Next.js?
Route Handler adalah fungsi yang didefinisikan di dalam direktori app
dari sebuah proyek Next.js yang menangani permintaan HTTP yang masuk. Berbeda dengan pendekatan pages/api
yang lebih lama (yang menggunakan Rute API), Route Handler menawarkan cara yang lebih ramping dan fleksibel untuk mendefinisikan titik akhir API di samping komponen React Anda. Pada dasarnya, mereka adalah fungsi serverless yang dieksekusi di edge atau lingkungan server pilihan Anda.
Anggaplah Route Handler sebagai logika backend dari aplikasi Next.js Anda, yang bertanggung jawab untuk memproses permintaan, berinteraksi dengan basis data, dan mengembalikan respons.
Manfaat Menggunakan Route Handler
- Kolokasi: Route Handler berada langsung di samping komponen React Anda di dalam direktori
app
, mendorong organisasi dan pemeliharaan kode yang lebih baik. - Dukungan TypeScript: Dukungan TypeScript bawaan memastikan keamanan tipe dan meningkatkan pengalaman pengembang.
- Integrasi Middleware: Mudah mengintegrasikan middleware untuk tugas-tugas seperti autentikasi, otorisasi, dan validasi permintaan.
- Dukungan Streaming: Route Handler dapat melakukan streaming data, memungkinkan Anda mengirim respons secara bertahap, yang bermanfaat untuk kumpulan data besar atau proses yang berjalan lama.
- Edge Functions: Terapkan Route Handler sebagai Edge Functions untuk respons latensi rendah yang lebih dekat dengan pengguna Anda, memanfaatkan CDN global.
- Desain API yang Disederhanakan: Route Handler menyediakan API yang bersih dan intuitif untuk menangani permintaan dan respons.
- Integrasi Server Actions: Integrasi yang erat dengan Server Actions memungkinkan komunikasi yang lancar antara komponen sisi klien dan logika sisi server Anda.
Menyiapkan Proyek Next.js Anda
Sebelum mendalami Route Handler, pastikan Anda telah menyiapkan proyek Next.js dengan direktori app
. Jika Anda memulai proyek baru, gunakan perintah berikut:
npx create-next-app@latest my-nextjs-app
Pilih direktori app
selama proses penyiapan untuk mengaktifkan sistem rute yang baru.
Membuat Route Handler Pertama Anda
Mari kita buat titik akhir API sederhana yang mengembalikan respons JSON. Buat direktori baru di dalam direktori app
, misalnya, /app/api/hello
. Di dalam direktori ini, buat file bernama route.ts
(atau route.js
jika Anda tidak menggunakan TypeScript).
Berikut adalah kode untuk Route Handler pertama Anda:
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}
Penjelasan:
import { NextResponse } from 'next/server';
: Mengimpor objekNextResponse
, yang digunakan untuk menyusun respons API.export async function GET(request: Request) { ... }
: Mendefinisikan fungsi asinkron yang menangani permintaan GET ke titik akhir/api/hello
. Parameterrequest
menyediakan akses ke objek permintaan yang masuk.return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
: Membuat respons JSON dengan sebuah pesan dan mengembalikannya menggunakanNextResponse.json()
.
Sekarang, Anda dapat mengakses titik akhir ini dengan menavigasi ke /api/hello
di browser Anda atau menggunakan alat seperti curl
atau Postman
.
Menangani Metode HTTP yang Berbeda
Route Handler mendukung berbagai metode HTTP seperti GET, POST, PUT, DELETE, PATCH, dan OPTIONS. Anda dapat mendefinisikan fungsi terpisah untuk setiap metode di dalam file route.ts
yang sama.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Logika untuk mengambil semua pengguna dari basis data
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Contoh data
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // Urai badan permintaan sebagai JSON
// Logika untuk membuat pengguna baru di basis data menggunakan 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // Contoh
return NextResponse.json(newUser, { status: 201 }); // Kembalikan pengguna baru dengan kode status 201 Created
}
Penjelasan:
- Fungsi
GET
mengambil daftar pengguna (disimulasikan di sini) dan mengembalikannya sebagai respons JSON. - Fungsi
POST
mengurai badan permintaan sebagai JSON, membuat pengguna baru (disimulasikan), dan mengembalikan pengguna baru tersebut dengan kode status 201 Created.
Mengakses Data Request
Objek request
menyediakan akses ke berbagai informasi tentang permintaan yang masuk, termasuk header, parameter kueri, dan badan permintaan.
Header
Anda dapat mengakses header permintaan menggunakan properti request.headers
:
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
Parameter Kueri
Untuk mengakses parameter kueri, Anda dapat menggunakan konstruktor URL
:
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
Badan Request
Untuk permintaan POST, PUT, dan PATCH, Anda dapat mengakses badan permintaan menggunakan metode request.json()
atau request.text()
, tergantung pada tipe konten.
export async function POST(request: Request) {
const data = await request.json();
console.log('Data:', data);
return NextResponse.json({ receivedData: data });
}
Mengembalikan Respons
Objek NextResponse
digunakan untuk menyusun respons API. Objek ini menyediakan beberapa metode untuk mengatur header, kode status, dan badan respons.
Respons JSON
Gunakan metode NextResponse.json()
untuk mengembalikan respons JSON:
return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });
Respons Teks
Gunakan konstruktor new Response()
untuk mengembalikan respons teks biasa:
return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
Pengalihan (Redirect)
Gunakan NextResponse.redirect()
untuk mengalihkan pengguna ke URL yang berbeda:
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
Mengatur Header
Anda dapat mengatur header kustom menggunakan opsi headers
di NextResponse.json()
atau new Response()
:
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
Integrasi Middleware
Middleware memungkinkan Anda menjalankan kode sebelum sebuah permintaan ditangani oleh Route Handler Anda. Ini berguna untuk autentikasi, otorisasi, pencatatan (logging), dan masalah lintas-sektoral lainnya.
Untuk membuat middleware, buat file bernama middleware.ts
(atau middleware.js
) di direktori app
atau subdirektori mana pun. Middleware akan berlaku untuk semua rute di dalam direktori tersebut dan subdirektorinya.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // Terapkan middleware ini ke path yang dimulai dengan /protected/
};
Penjelasan:
- Fungsi
middleware
memeriksa token autentikasi di dalam cookie permintaan. - Jika token tidak ada, fungsi ini akan mengalihkan pengguna ke halaman login.
- Jika ada, fungsi ini mengizinkan permintaan untuk melanjutkan ke Route Handler.
- Objek
config
menetapkan bahwa middleware ini hanya berlaku untuk rute yang dimulai dengan/protected/
.
Penanganan Kesalahan (Error Handling)
Penanganan kesalahan yang tepat sangat penting untuk membangun API yang tangguh. Anda dapat menggunakan blok try...catch
untuk menangani pengecualian dan mengembalikan respons kesalahan yang sesuai.
export async function GET(request: Request) {
try {
// Simulasikan sebuah kesalahan
throw new Error('Something went wrong!');
} catch (error: any) {
console.error('Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Penjelasan:
- Blok
try...catch
menangkap setiap pengecualian yang terjadi di dalam Route Handler. - Di dalam blok
catch
, kesalahan dicatat, dan respons kesalahan dikembalikan dengan kode status 500 Internal Server Error.
Respons Streaming
Route Handler mendukung respons streaming, yang memungkinkan Anda mengirim data secara bertahap ke klien. Ini sangat berguna untuk kumpulan data besar atau proses yang berjalan lama.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simulasikan penundaan
yield `Data chunk ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
Penjelasan:
- Fungsi
generateData
adalah generator asinkron yang menghasilkan potongan data dengan penundaan. - Metode
Readable.from()
membuat stream yang dapat dibaca dari generator. - Objek
Response
dibuat dengan stream yang dapat dibaca sebagai badan, dan headerContent-Type
diatur ketext/plain
.
Autentikasi dan Otorisasi
Mengamankan titik akhir API Anda sangatlah penting. Anda dapat mengimplementasikan autentikasi dan otorisasi menggunakan middleware atau langsung di dalam Route Handler Anda.
Autentikasi
Autentikasi memverifikasi identitas pengguna yang membuat permintaan. Metode autentikasi umum meliputi:
- JWT (JSON Web Tokens): Hasilkan token saat login berhasil dan verifikasi pada permintaan berikutnya.
- Autentikasi berbasis Sesi: Gunakan cookie untuk menyimpan pengidentifikasi sesi dan verifikasi pada setiap permintaan.
- OAuth: Delegasikan autentikasi ke penyedia pihak ketiga seperti Google atau Facebook.
Berikut adalah contoh autentikasi JWT menggunakan middleware:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // Ganti dengan rahasia yang kuat dan dibuat secara acak
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
Otorisasi
Otorisasi menentukan sumber daya apa yang boleh diakses oleh pengguna. Ini biasanya didasarkan pada peran atau izin.
Anda dapat mengimplementasikan otorisasi di dalam Route Handler Anda dengan memeriksa peran atau izin pengguna dan mengembalikan kesalahan jika mereka tidak memiliki akses.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Asumsikan Anda memiliki fungsi untuk mendapatkan peran pengguna dari token atau sesi
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
}
// Logika untuk mengambil data admin
const adminData = { message: 'Admin data' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// Ganti dengan logika Anda yang sebenarnya untuk mengekstrak peran pengguna dari permintaan
// Ini bisa melibatkan verifikasi token JWT atau memeriksa sesi
return 'admin'; // Contoh: peran yang di-hardcode untuk demonstrasi
}
Menerapkan (Deploy) Route Handler
Route Handler diterapkan sebagai fungsi serverless pada penyedia hosting pilihan Anda. Next.js mendukung berbagai platform penerapan, termasuk Vercel, Netlify, AWS, dan lainnya.
Untuk Vercel, penerapannya semudah menghubungkan repositori Git Anda ke Vercel dan mendorong kode Anda. Vercel secara otomatis mendeteksi proyek Next.js Anda dan menerapkan Route Handler Anda sebagai fungsi serverless.
Teknik Tingkat Lanjut
Edge Functions
Route Handler dapat diterapkan sebagai Edge Functions, yang dieksekusi di tepi CDN, lebih dekat dengan pengguna Anda. Hal ini dapat secara signifikan mengurangi latensi dan meningkatkan kinerja.
Untuk menerapkan Route Handler sebagai Edge Function, tambahkan runtime edge
ke file route.ts
Anda:
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from the Edge!' });
}
Server Actions
Server Actions memungkinkan Anda mengeksekusi kode sisi server langsung dari komponen React Anda. Route Handler dan Server Actions bekerja sama dengan mulus, memungkinkan Anda membangun aplikasi yang kompleks dengan mudah.
Berikut adalah contoh penggunaan Server Action untuk memanggil Route Handler:
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // Segarkan halaman untuk mencerminkan perubahan
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
Caching
Caching dapat secara signifikan meningkatkan kinerja titik akhir API Anda. Anda dapat menggunakan header Cache-Control
untuk mengontrol bagaimana respons Anda di-cache oleh browser dan CDN.
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
Contoh ini mengatur header Cache-Control
ke public, max-age=3600
, yang memberitahu browser dan CDN untuk menyimpan respons dalam cache selama satu jam.
Praktik Terbaik
- Gunakan TypeScript: Manfaatkan keamanan tipe TypeScript untuk meningkatkan kualitas kode dan mencegah kesalahan.
- Validasi Permintaan: Validasi permintaan yang masuk untuk memastikan integritas data dan mencegah input berbahaya.
- Tangani Kesalahan dengan Baik: Terapkan penanganan kesalahan yang tepat untuk memberikan pesan kesalahan yang informatif kepada klien.
- Amankan Titik Akhir Anda: Terapkan autentikasi dan otorisasi untuk melindungi titik akhir API Anda.
- Gunakan Middleware: Gunakan middleware untuk masalah lintas-sektoral seperti autentikasi, pencatatan (logging), dan validasi permintaan.
- Cache Respons: Gunakan caching untuk meningkatkan kinerja titik akhir API Anda.
- Pantau API Anda: Pantau API Anda untuk mengidentifikasi dan menyelesaikan masalah dengan cepat.
- Dokumentasikan API Anda: Dokumentasikan API Anda agar mudah digunakan oleh pengembang lain. Pertimbangkan untuk menggunakan alat seperti Swagger/OpenAPI untuk dokumentasi API.
Contoh Dunia Nyata
Berikut adalah beberapa contoh dunia nyata tentang bagaimana Route Handler dapat digunakan:
- API E-commerce: Buat titik akhir API untuk mengelola produk, pesanan, dan pengguna.
- API Media Sosial: Buat titik akhir API untuk memposting tweet, mengikuti pengguna, dan mengambil linimasa.
- API Sistem Manajemen Konten (CMS): Buat titik akhir API untuk mengelola konten, pengguna, dan pengaturan.
- API Analitik Data: Buat titik akhir API untuk mengumpulkan dan menganalisis data. Sebagai contoh, sebuah Route Handler dapat menerima data dari piksel pelacakan di berbagai situs web dan menggabungkan informasi tersebut untuk pelaporan.
Contoh E-commerce Internasional: Sebuah Route Handler digunakan untuk mengambil harga produk berdasarkan negara pengguna. Titik akhir dapat menggunakan geolokasi permintaan (diperoleh dari alamat IP) untuk menentukan lokasi pengguna dan mengembalikan harga dalam mata uang yang sesuai. Hal ini berkontribusi pada pengalaman belanja yang terlokalisasi.
Contoh Autentikasi Global: Sebuah Route Handler yang mengimplementasikan autentikasi multi-faktor (MFA) untuk pengguna di seluruh dunia. Ini bisa melibatkan pengiriman kode SMS atau menggunakan aplikasi otentikator, sambil menghormati peraturan privasi dan infrastruktur telekomunikasi di berbagai wilayah.
Pengiriman Konten Multibahasa: Sebuah Route Handler yang mengirimkan konten dalam bahasa pilihan pengguna. Ini dapat ditentukan dari header `Accept-Language` dalam permintaan. Contoh ini menyoroti perlunya pengkodean UTF-8 yang tepat dan dukungan bahasa kanan-ke-kiri jika sesuai.
Kesimpulan
Route Handler Next.js menyediakan cara yang kuat dan fleksibel untuk membuat titik akhir API langsung di dalam aplikasi Next.js Anda. Dengan memanfaatkan Route Handler, Anda dapat membangun API yang tangguh dengan mudah, menempatkan logika backend Anda bersama komponen React Anda, dan memanfaatkan fitur-fitur seperti middleware, streaming, dan Edge Functions.
Panduan komprehensif ini telah mencakup semuanya, mulai dari penyiapan dasar hingga teknik tingkat lanjut. Dengan mengikuti praktik terbaik yang diuraikan dalam panduan ini, Anda dapat membangun API berkualitas tinggi yang aman, berkinerja, dan dapat dipelihara.