Ketika saya membangun API produksi pertama saya, saya menggunakan Express.js dan pengaturannya memakan waktu sekitar dua jam: boilerplate, middleware, route handler, konfigurasi TypeScript, dan skrip penerapan. Baru-baru ini, saya berhasil merilis REST API lengkap hanya dalam 20 menit menggunakan NitroJs. Tanpa rantai app.use(), tanpa routing manual, tanpa pusing masalah penerapan.
Panduan ini menunjukkan bagaimana NitroJs menghilangkan boilerplate sambil memberikan Anda backend siap produksi yang berjalan di mana saja, Node, Bun, Deno, serverless, atau edge.
Apa Itu NitroJs dan Mengapa Menggunakannya untuk API Backend?
NitroJs adalah toolkit server dari ekosistem UnJS yang memperlakukan backend Anda sebagai artefak build. Alih-alih menulis server yang terikat pada runtime, Anda menulis route handler dan Nitro mengompilasinya menjadi bundel portabel. Terapkan kode yang sama ke Node.js, Cloudflare Workers, Vercel, atau kontainer Docker tanpa mengubah satu baris pun.

Model mental inti: Tulis rute, bukan server. Anda fokus pada logika API; Nitro menangani HTTP, middleware, dan koneksi platform.
Keunggulan utama untuk API backend:
- Konfigurasi nol: Tanpa boilerplate
server.js - Routing berbasis sistem berkas:
routes/users.get.tsmenjadiGET /users - Native TypeScript: Tipe otomatis diinferensikan dari handler
- Penerapan universal: Satu build, banyak target
- Caching bawaan: Menyimpan respons API di memori, Redis, atau Cloudflare KV
- Lapisan penyimpanan: Sistem berkas abstrak untuk data sementara
Bagi pengembang API, ini berarti Anda merilis lebih cepat dan lebih sedikit melakukan refaktor saat mengubah infrastruktur.
Memulai: Instal NitroJs dalam 5 Menit
Langkah 1: Menyiapkan Proyek
# Menggunakan pnpm (disarankan)
pnpm dlx giget@latest nitro nitro-api-backend
# Atau npm
npm create nitro@latest nitro-api-backend
# Atau bun
bunx giget@latest nitro nitro-api-backend
Ini mengkloning template starter resmi ke dalam nitro-api-backend.
Langkah 2: Menjelajahi Struktur
cd nitro-api-backend
tree -L 2
Output:
├── server
│ ├── api
│ ├── routes
│ ├── tasks
│ └── middleware
├── nitro.config.ts
├── package.json
└── tsconfig.json
Direktori penting:
server/api/: Rute API (tanpa UI)server/routes/: Rute full-stack (untuk SSR)server/middleware/: Middleware globalserver/tasks/: Tugas latar belakang
Untuk API backend murni, abaikan routes dan letakkan semuanya di api.
Langkah 3: Menjalankan Server Pengembangan
pnpm install
pnpm dev
Nitro dimulai di http://localhost:3000 dengan hot reload. Edit berkas, dan server akan dimulai ulang dalam waktu kurang dari 200ms.

Membangun Endpoint API Pertama Anda
Penangan GET Sederhana
Buat server/api/users.get.ts:
// server/api/users.get.ts
export default defineEventHandler(() => {
return [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
});
Nitro secara otomatis menyajikan ini di GET /api/users. Pembungkus defineEventHandler menyediakan keamanan tipe dan akses ke konteks permintaan.
Rute Dinamis dengan Parameter
Buat server/api/users/[id].get.ts:
// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id');
if (!id) {
throw createError({
statusCode: 400,
statusMessage: 'User ID is required'
});
}
return {
id: Number(id),
name: `User ${id}`,
email: `user${id}@example.com`
};
});
Akses GET /api/users/42 untuk melihat { id: 42, name: "User 42", ... }.
Permintaan POST dengan Badan JSON
Buat server/api/users.post.ts:
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
// Nitro secara otomatis mengurai JSON
const { name, email } = body;
if (!name || !email) {
throw createError({
statusCode: 422,
statusMessage: 'Name and email are required'
});
}
// Mensimulasikan penyisipan database
const newUser = {
id: Math.floor(Math.random() * 1000),
name,
email,
createdAt: new Date().toISOString()
};
return newUser;
});
Uji ini:
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'
Respons Aman Tipe
Nitro menginferensi tipe respons dari nilai kembalian Anda. Untuk kontrak yang ketat, gunakan tipe eksplisit:
// server/api/products.get.ts
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
export default defineEventHandler<Product[]>(() => {
return [
{ id: 1, name: "Laptop", price: 1299.99, inStock: true },
{ id: 2, name: "Mouse", price: 29.99, inStock: false }
];
});
Sekarang klien yang mengimpor endpoint ini mendapatkan IntelliSense penuh.
Pola API Tingkat Lanjut
Middleware untuk Otentikasi
Buat server/middleware/auth.ts:
// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
const protectedRoutes = ['/api/admin', '/api/users/me'];
if (protectedRoutes.some(route => event.path.startsWith(route))) {
const token = getHeader(event, 'authorization')?.replace('Bearer ', '');
if (!token || token !== process.env.API_SECRET) {
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized'
});
}
}
});
Middleware berjalan sebelum setiap rute. Tambahkan ke nitro.config.ts:
// nitro.config.ts
export default defineNitroConfig({
srcDir: 'server',
runtimeConfig: {
apiSecret: process.env.API_SECRET
}
});
Melakukan Caching Respons API
Cache komputasi mahal selama 60 detik:
// server/api/stats.get.ts
export default defineCachedEventHandler(async () => {
const db = useStorage('data');
const users = await db.getItem('users') || [];
return {
totalUsers: users.length,
activeUsers: users.filter(u => u.lastSeen > Date.now() - 86400000).length
};
}, {
maxAge: 60, // detik
name: 'stats',
getKey: () => 'global-stats'
});
Nitro menangani invalidasi cache dan penyimpanan (memori, Redis, atau Cloudflare KV berdasarkan target penerapan).
Penanganan Unggah Berkas
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
const files = await readMultipartFormData(event);
if (!files?.length) {
throw createError({ statusCode: 400, statusMessage: 'No files uploaded' });
}
const storage = useStorage('uploads');
const file = files[0];
await storage.setItem(file.filename, file.data);
return { success: true, filename: file.filename };
});
Uji dengan:
curl -X POST http://localhost:3000/api/upload \
-F "file=@/path/to/image.jpg"
Penerapan: Dari Lokal ke Produksi
Membangun untuk Produksi
pnpm build
Nitro menghasilkan direktori .output dengan titik masuk khusus platform.
Menjalankan di Node.js
node .output/server/index.mjs
Tidak diperlukan node_modules—build mengemas semuanya.
Menerapkan ke Cloudflare Workers
# Instal preset
pnpm add -D nitro-preset-cloudflare-workers
# Build dengan preset
NITRO_PRESET=cloudflare-workers pnpm build
# Terapkan
wrangler deploy .output
Menerapkan ke Vercel (Tanpa Server)
# Vercel mendeteksi Nitro secara otomatis
vercel
Atau konfigurasikan nitro.config.ts:
export default defineNitroConfig({
preset: 'vercel-edge'
});
Variabel Lingkungan
Buat .env secara lokal, lalu gunakan dasbor platform di produksi:
# .env
API_SECRET=dev-secret-key
DATABASE_URL=file:./dev.db
Akses di handler:
const config = useRuntimeConfig();
const secret = config.apiSecret;
Kasus Penggunaan Lanjutan
WebSockets & Server-Sent Events
Nitro mendukung WebSockets melalui defineWebSocketHandler:
// server/api/ws.ts
export default defineWebSocketHandler({
open(peer) {
console.log('WebSocket terhubung:', peer);
},
message(peer, message) {
peer.send(`Echo: ${message.text()}`);
},
close(peer, details) {
console.log('WebSocket ditutup:', details);
}
});
Akses di ws://localhost:3000/api/ws.
Tugas Latar Belakang
Buat server/tasks/cleanup.ts:
// server/tasks/cleanup.ts
export default defineCronHandler('0 2 * * *', async () => {
const db = useStorage('temp');
const keys = await db.getKeys();
for (const key of keys) {
const metadata = await db.getMeta(key);
if (metadata.expiresAt < Date.now()) {
await db.removeItem(key);
}
}
console.log('Pembersihan selesai');
});
Ini berjalan setiap hari pukul 2 pagi. Terapkan ke platform dengan dukungan cron (misalnya, Vercel, Netlify).
Mesin Alur Kerja
Integrasikan dengan useWorkflow.dev untuk orkestrasi kompleks:
// server/api/workflows/process.ts
import { createWorkflow } from '@useworkflow/sdk';
export default defineEventHandler(async (event) => {
const workflow = createWorkflow('data-pipeline', {
steps: [
{ id: 'fetch', run: 'https://api.example.com/data' },
{ id: 'transform', run: 'transform.js' },
{ id: 'store', run: async (data) => {
const storage = useStorage('results');
await storage.setItem('latest', data);
}}
]
});
await workflow.start();
return { status: 'dimulai' };
});
Skenario Pengembang Nyata
Skenario 1: Backend Situs Statis
Terapkan Nitro API ke Cloudflare Workers yang menyajikan data JSON ke situs JAMstack statis. Tingkat gratis menangani 100 ribu permintaan/hari.
Skenario 2: API Aplikasi Seluler
Bangun endpoint REST untuk aplikasi React Native. Gunakan penanganan CORS bawaan Nitro:
// nitro.config.ts
export default defineNitroConfig({
routeRules: {
'/api/**': { cors: true }
}
});
Skenario 3: Gateway Microservices
Jalankan Nitro sebagai gateway API yang mengagregasi microservices. Gunakan $fetch untuk memproksi permintaan:
// server/api/aggregate.get.ts
export default defineEventHandler(async (event) => {
const [users, posts] = await Promise.all([
$fetch('https://users-service.internal/users'),
$fetch('https://posts-service.internal/posts')
]);
return { users, posts };
});
Uji API NitroJs Anda dengan Apidog
Nitro menghasilkan backend dengan cepat, tetapi kecepatan tidak berarti apa-apa jika endpoint Anda rusak. Saat Anda merilis POST /api/users baru, impor definisi rute ke Apidog. Ini merekayasa balik tipe kembalian handler Anda dan secara otomatis menghasilkan tes kontrak.

Jalankan di CI untuk menangkap perubahan yang merusak sebelum tim frontend Anda frustrasi. Gratis untuk memulai, dan itu adalah batasan yang dibutuhkan pengembangan Nitro Anda yang cepat.
Pertanyaan yang Sering Diajukan
1. Bisakah Nitro menggantikan Express.js sepenuhnya?
Ya. Nitro menangani routing, middleware, dan penerapan dengan lebih baik. Migrasi dengan memindahkan middleware Express ke plugin Nitro dan rute ke server/api/.
2. Bagaimana Nitro menangani koneksi database?
Gunakan plugin Nitro untuk menginisialisasi pool saat startup. Lapisan penyimpanan mengabstraksi caching, tetapi untuk SQL, gunakan ORM Anda sendiri (Prisma, Drizzle).
3. Apakah Nitro siap produksi?
Tentu saja. Nuxt menggunakan Nitro untuk jutaan situs produksi. Ini sudah teruji dalam skala besar.
4. Bisakah saya menggunakan Nitro dengan GraphQL?
Ya. Tambahkan handler GraphQL di server/api/graphql.post.ts. Gunakan pustaka GraphQL Node apa pun—Nitro tidak membatasi Anda.
5. Apa perbedaan antara Nitro dan Hono?
Hono adalah router yang ringan. Nitro adalah toolkit server lengkap dengan build, preset, dan penyimpanan. Gunakan Hono untuk microservices, Nitro untuk backend lengkap.
Kesimpulan
NitroJs memikirkan ulang pengembangan backend dengan mengompilasi API Anda menjadi artefak portabel. Anda mendapatkan routing sistem berkas, keamanan TypeScript, dan penerapan universal tanpa boilerplate. Bangun REST API Anda berikutnya dengan Nitro, dan validasi dengan Apidog. Anda di masa depan akan berterima kasih ketika Anda bermigrasi dari Node ke edge hanya dengan satu baris konfigurasi.
