Nuxt Nitro dan Server Routes di 2026: Full-Stack Vue dan API Endpoints
Pelajari cara menguasai Nuxt Nitro server routes untuk membangun aplikasi Vue full-stack. Tutorial lengkap API endpoints, middleware, integrasi database, dan deployment production dengan Nuxt 4.

Nuxt Nitro mengubah aplikasi Vue menjadi platform full-stack yang powerful dengan menyediakan engine server universal yang menangani API routes, middleware, dan logika server-side bersamaan dengan komponen frontend. Dengan Nuxt 4.3 dan Nitro v3 yang akan datang, membangun backend siap-production tidak pernah semudah ini terintegrasi dengan pengembangan Vue.
Nitro memungkinkan berbagi tipe TypeScript antara frontend dan backend, menghilangkan perbedaan kontrak API dan mengurangi boilerplate. Server routes berada di server/api/ dan otomatis tersedia di endpoint /api/*.
Memahami Arsitektur Nuxt Nitro Server Engine
Nitro berfungsi sebagai runtime server JavaScript universal yang menggerakkan direktori server Nuxt. Berbeda dengan server Node.js tradisional, Nitro mengkompilasi menjadi bundle yang dioptimalkan untuk platform dan dapat di-deploy dengan mulus ke Vercel, Netlify, Cloudflare Workers, dan lingkungan Node.js standar tanpa perubahan kode.
Arsitekturnya memisahkan concerns melalui konvensi direktori:
export default defineEventHandler(async (event) => {
// Nitro auto-serializes return values to JSON
// HTTP method suffix (.get.ts) restricts to GET requests
const users = await getUsersFromDatabase()
return { users, count: users.length }
})Nitro memindai empat direktori: server/api untuk API routes dengan prefix /api, server/routes untuk routes tanpa prefix, server/middleware untuk request interceptors, dan server/utils untuk shared server utilities. File di luar direktori ini tetap tidak terlihat oleh server runtime.
Membuat RESTful API Endpoints dengan defineEventHandler
Server routes mengikuti konvensi file-based routing dimana nama file langsung dipetakan ke URL paths. Suffix HTTP method mengontrol request mana yang diterima setiap handler.
// Handles GET /api/products/123
export default defineEventHandler(async (event) => {
// Extract route parameter from URL
const id = getRouterParam(event, 'id')
if (!id) {
throw createError({
status: 400, // Nuxt 4 uses Web API naming (not statusCode)
statusText: 'Product ID required' // Not statusMessage
})
}
const product = await fetchProduct(id)
if (!product) {
throw createError({
status: 404,
statusText: 'Product not found'
})
}
return product
})Nuxt 4 mengadopsi konvensi penamaan Web API sebagai persiapan untuk Nitro v3. Property statusCode menjadi status, dan statusMessage menjadi statusText. Meskipun property lama masih berfungsi, migrasi ke penamaan baru memastikan kompatibilitas dengan Nuxt 5.
Menangani POST requests dengan validasi body:
// Handles POST /api/products
import { z } from 'zod'
const ProductSchema = z.object({
name: z.string().min(1).max(200),
price: z.number().positive(),
category: z.enum(['electronics', 'clothing', 'food'])
})
export default defineEventHandler(async (event) => {
// readBody automatically parses JSON
const body = await readBody(event)
// Validate with Zod schema
const result = ProductSchema.safeParse(body)
if (!result.success) {
throw createError({
status: 422,
statusText: 'Validation failed',
data: result.error.flatten()
})
}
const product = await createProduct(result.data)
// Set 201 Created status for resource creation
setResponseStatus(event, 201)
return product
})Server Middleware untuk Autentikasi dan Logging
File middleware dieksekusi sebelum route handlers, memungkinkan cross-cutting concerns seperti autentikasi, logging, dan transformasi request. Berbeda dengan route handlers, middleware tidak mengembalikan response secara langsung.
export default defineEventHandler(async (event) => {
// Skip auth for public routes
const publicRoutes = ['/api/health', '/api/auth/login']
if (publicRoutes.includes(event.path)) {
return // Continue to next handler
}
const authHeader = getHeader(event, 'authorization')
if (!authHeader?.startsWith('Bearer ')) {
throw createError({
status: 401,
statusText: 'Authentication required'
})
}
const token = authHeader.slice(7)
try {
// Verify JWT and attach user to event context
const user = await verifyToken(token)
event.context.user = user
} catch {
throw createError({
status: 401,
statusText: 'Invalid or expired token'
})
}
})Objek event.context bertahan di seluruh middleware dan handlers dalam satu request, menyediakan cara type-safe untuk berbagi data. Definisikan tipe context dalam file deklarasi:
declare module 'h3' {
interface H3EventContext {
user?: {
id: string
email: string
role: 'admin' | 'user'
}
}
}Untuk persiapan wawancara tentang konsep Nuxt server, tinjau modul pertanyaan wawancara Nuxt Server Routes.
Siap menguasai wawancara Vue.js / Nuxt.js Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Integrasi Database dengan Prisma dan Server Utils
Server utilities di server/utils/ auto-import di seluruh kode server, membuat database clients dan logika bersama dapat diakses tanpa import eksplisit.
import { PrismaClient } from '@prisma/client'
// Singleton pattern prevents multiple instances in development
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma = globalForPrisma.prisma ?? new PrismaClient({
log: process.env.NODE_ENV === 'development'
? ['query', 'error', 'warn']
: ['error']
})
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}Dengan database client tersedia secara global, route handlers dapat mengaksesnya langsung:
export default defineEventHandler(async (event) => {
// Query parameters for pagination
const query = getQuery(event)
const page = Number(query.page) || 1
const limit = Math.min(Number(query.limit) || 10, 100)
const skip = (page - 1) * limit
// Parallel queries for data and count
const [posts, total] = await Promise.all([
prisma.post.findMany({
skip,
take: limit,
orderBy: { createdAt: 'desc' },
include: { author: { select: { name: true, avatar: true } } }
}),
prisma.post.count()
])
return {
posts,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
}
})Server Plugins untuk Inisialisasi Runtime
Server plugins di server/plugins/ dieksekusi sekali saat server dimulai, ideal untuk menginisialisasi koneksi, menjadwalkan tasks, atau menyiapkan monitoring.
export default defineNitroPlugin(async (nitroApp) => {
// Verify database connection on startup
try {
await prisma.$connect()
console.log('Database connected successfully')
} catch (error) {
console.error('Database connection failed:', error)
process.exit(1) // Fail fast if DB unavailable
}
// Graceful shutdown hook
nitroApp.hooks.hook('close', async () => {
await prisma.$disconnect()
console.log('Database disconnected')
})
})Sistem plugin terintegrasi dengan Nitro hooks untuk lifecycle management. Hooks diaktifkan pada titik tertentu: request sebelum handling, beforeResponse sebelum mengirim, dan close saat shutdown.
Panggilan API Type-Safe dari Vue Components
Utility $fetch Nuxt menyediakan type inference dari server routes saat menggunakan alias ~/server. Dikombinasikan dengan composable useFetch, komponen mengkonsumsi API dengan dukungan TypeScript penuh.
<script setup lang="ts">
// Inferred return type from server/api/products/[id].get.ts
const route = useRoute()
const { data: product, status, error } = await useFetch(
`/api/products/${route.params.id}`
)
// Mutation with optimistic updates
const { execute: updateProduct, status: updateStatus } = useFetch(
`/api/products/${route.params.id}`,
{
method: 'PATCH',
immediate: false, // Don't fetch on mount
watch: false // Don't refetch on dependency change
}
)
async function handleUpdate(updates: Partial<Product>) {
await updateProduct({ body: updates })
// Refetch to sync state
await refreshNuxtData(`product-${route.params.id}`)
}
</script>
<template>
<div v-if="status === 'pending'">Loading...</div>
<div v-else-if="error">{{ error.message }}</div>
<ProductDetail v-else :product="product" @update="handleUpdate" />
</template>Strategi Caching untuk Server Routes
Nuxt 4.3 memperkenalkan kontrol caching yang ditingkatkan melalui routeRules di nuxt.config.ts. Server routes mendapat manfaat dari infrastruktur caching yang sama seperti pages.
export default defineNuxtConfig({
routeRules: {
// Cache product listings for 5 minutes
'/api/products': {
cache: {
maxAge: 300,
staleMaxAge: 600, // Serve stale while revalidating
swr: true
}
},
// No cache for user-specific data
'/api/user/**': { cache: false },
// Pre-render static API responses at build time
'/api/categories': { prerender: true }
}
})Untuk invalidasi cache dinamis, gunakan wrapper defineCachedEventHandler:
export default defineCachedEventHandler(async (event) => {
const trending = await calculateTrendingProducts()
return trending
}, {
maxAge: 60 * 5, // 5 minutes
name: 'trending-products',
getKey: () => 'trending', // Cache key for invalidation
shouldBypassCache: (event) => {
// Bypass for admin users
return event.context.user?.role === 'admin'
}
})Penanganan Error dan Format Response
Response error yang konsisten meningkatkan usability API. Buat utilitas error handler bersama:
import { H3Error } from 'h3'
export function handleDatabaseError(error: unknown): never {
console.error('Database error:', error)
// Prisma-specific error handling
if (error instanceof Error && 'code' in error) {
const prismaError = error as { code: string }
if (prismaError.code === 'P2002') {
throw createError({
status: 409,
statusText: 'Resource already exists'
})
}
if (prismaError.code === 'P2025') {
throw createError({
status: 404,
statusText: 'Resource not found'
})
}
}
throw createError({
status: 500,
statusText: 'Internal server error'
})
}Untuk pola Vue.js yang komprehensif dan state management, jelajahi artikel perbandingan Pinia vs Vuex.
Sebelum men-deploy Nitro servers: validasi environment variables dengan skema Zod, implementasikan rate limiting middleware, tambahkan request logging untuk debugging, dan konfigurasi CORS headers untuk akses API cross-origin.
Deployment Lintas Platform
Sistem preset Nitro menghasilkan build yang dioptimalkan untuk setiap platform:
export default defineNuxtConfig({
nitro: {
// Auto-detected on Vercel/Netlify, or specify manually
preset: 'node-server', // 'vercel', 'netlify', 'cloudflare-workers'
// Compress responses
compressPublicAssets: true,
// External packages not to bundle
externals: {
external: ['@prisma/client']
}
}
})Untuk deployment Node.js, output mencakup server standalone:
# Build for production
npm run build
# Start the server
node .output/server/index.mjsNuxt 3 mencapai end-of-life pada 31 Juli 2026. Proyek harus bermigrasi ke Nuxt 4 menggunakan panduan migrasi resmi. Nuxt 5 dengan Nitro v3 menyusul segera setelahnya.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Kesimpulan
- Server routes di
server/api/otomatis dipetakan ke endpoint/api/*dengan suffix HTTP method (.get.ts,.post.ts) mengontrol tipe request - Middleware di
server/middleware/menangani autentikasi, logging, dan transformasi request sebelum routes dieksekusi - Objek
event.contextmembagikan data yang di-type antara middleware dan handlers dalam satu request - Server utils di
server/utils/auto-import di seluruh kode server, ideal untuk database clients dan logika bersama - Nuxt 4 mengadopsi penamaan Web API (
status/statusText) sebagai persiapan untuk Nitro v3 defineCachedEventHandlermenyediakan caching level route dengan kontrol invalidasi- Preset Nitro memungkinkan deployment tanpa konfigurasi ke Vercel, Netlify, Cloudflare, dan server Node.js
Tag
Bagikan
Artikel terkait

Nuxt 4 di Tahun 2026: Struktur Direktori Baru dan Panduan Migrasi dari Nuxt 3
Panduan lengkap Nuxt 4 mencakup struktur direktori app/, singleton data fetching, shallow reactivity, serta langkah migrasi bertahap dari Nuxt 3 untuk developer Vue.js.

Vue 3 Composables Tingkat Lanjut: Pola yang Dapat Digunakan Ulang dan Pertanyaan Interview 2026
Panduan lengkap Vue 3 composables tingkat lanjut: pola yang dapat digunakan ulang, penanganan asinkron, dependency injection, validasi form, pengujian terisolasi, dan pertanyaan interview teknis 2026.

Pengujian Vue 3 di 2026: Vitest, Vue Test Utils, dan Pertanyaan Wawancara
Panduan praktis pengujian Vue di 2026: konfigurasi Vitest, memasang komponen dengan Vue Test Utils, menguji composable dan store Pinia, memocking API, mengukur coverage, serta pertanyaan wawancara yang diajukan tim perekrut.