# Nuxt Nitro và Server Routes năm 2026: Full-Stack Vue và API Endpoints > Làm chủ Nuxt Nitro server routes để xây dựng ứng dụng Vue full-stack. Hướng dẫn chi tiết về API endpoints, middleware, tích hợp database và triển khai production với Nuxt 4. - Published: 2026-07-16 - Updated: 2026-07-16 - Author: SharpSkill - Tags: nuxt, nitro, vue, full-stack, api, server-routes - Reading time: 12 min --- Nuxt Nitro biến đổi các ứng dụng Vue thành nền tảng full-stack mạnh mẽ bằng cách cung cấp engine server đa năng xử lý API routes, middleware và logic server-side song song với các component frontend. Với Nuxt 4.3 và Nitro v3 sắp ra mắt, việc xây dựng backend sẵn sàng cho production chưa bao giờ tích hợp tốt hơn với phát triển Vue. > **Full-Stack trong Một Repository** > > Nitro cho phép chia sẻ TypeScript types giữa frontend và backend, loại bỏ sự khác biệt trong API contract và giảm boilerplate. Server routes nằm trong `server/api/` và tự động khả dụng tại các endpoint `/api/*`. ## Hiểu về Kiến trúc Nuxt Nitro Server Engine Nitro đóng vai trò là runtime server JavaScript đa năng cung cấp sức mạnh cho thư mục server của Nuxt. Khác với server Node.js truyền thống, Nitro biên dịch thành các bundle được tối ưu hóa cho từng platform và có thể triển khai liền mạch tới [Vercel](https://vercel.com/docs/frameworks/nuxt), [Netlify](https://docs.netlify.com/frameworks/nuxt/), Cloudflare Workers và môi trường Node.js tiêu chuẩn mà không cần thay đổi code. Kiến trúc phân tách các concerns thông qua các quy ước thư mục: ```typescript // server/api/users.get.ts 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 quét bốn thư mục: `server/api` cho API routes với prefix `/api`, `server/routes` cho routes không có prefix, `server/middleware` cho request interceptors, và `server/utils` cho các server utilities dùng chung. Các file nằm ngoài những thư mục này sẽ không hiển thị với server runtime. ## Tạo RESTful API Endpoints với defineEventHandler Server routes tuân theo quy ước file-based routing trong đó tên file được ánh xạ trực tiếp tới URL paths. Hậu tố HTTP method kiểm soát request nào mỗi handler chấp nhận. ```typescript // server/api/products/[id].get.ts // 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 áp dụng quy ước đặt tên Web API để chuẩn bị cho Nitro v3. Property `statusCode` trở thành `status`, và `statusMessage` trở thành `statusText`. Mặc dù các property cũ vẫn hoạt động, việc chuyển sang đặt tên mới đảm bảo tương thích với Nuxt 5. Xử lý POST requests với validation body: ```typescript // server/api/products/index.post.ts // 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 cho Authentication và Logging Các file middleware được thực thi trước route handlers, cho phép các cross-cutting concerns như authentication, logging và biến đổi request. Khác với route handlers, middleware không trả về response trực tiếp. ```typescript // server/middleware/auth.ts 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' }) } }) ``` Đối tượng `event.context` tồn tại xuyên suốt middleware và handlers trong một request duy nhất, cung cấp cách type-safe để chia sẻ dữ liệu. Định nghĩa context types trong file khai báo: ```typescript // server/types/context.d.ts declare module 'h3' { interface H3EventContext { user?: { id: string email: string role: 'admin' | 'user' } } } ``` Để chuẩn bị phỏng vấn về các khái niệm Nuxt server, hãy xem module [câu hỏi phỏng vấn Nuxt Server Routes](/technologies/vue-nuxt/interview-questions/nuxt-server-routes). ## Tích hợp Database với Prisma và Server Utils Server utilities trong `server/utils/` tự động import xuyên suốt toàn bộ server code, giúp database clients và logic dùng chung có thể truy cập mà không cần import rõ ràng. ```typescript // server/utils/db.ts 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 } ``` Với database client có sẵn toàn cục, route handlers có thể truy cập trực tiếp: ```typescript // server/api/posts/index.get.ts 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 cho Runtime Initialization Server plugins trong `server/plugins/` được thực thi một lần khi server khởi động, lý tưởng để khởi tạo kết nối, lập lịch tasks, hoặc thiết lập monitoring. ```typescript // server/plugins/database.ts 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') }) }) ``` Hệ thống plugin tích hợp với [Nitro hooks](https://nitro.unjs.io/guide/plugins) để quản lý lifecycle. Hooks được kích hoạt tại các điểm cụ thể: `request` trước khi xử lý, `beforeResponse` trước khi gửi, và `close` trong khi shutdown. ## Gọi API Type-Safe từ Vue Components Utility `$fetch` của Nuxt cung cấp type inference từ server routes khi sử dụng alias `~/server`. Kết hợp với [composable useFetch](/technologies/vue-nuxt/interview-questions/nuxt-data-fetching), các component sử dụng APIs với hỗ trợ TypeScript đầy đủ. ```vue ``` ## Chiến lược Caching cho Server Routes Nuxt 4.3 giới thiệu các điều khiển caching nâng cao thông qua `routeRules` trong `nuxt.config.ts`. Server routes được hưởng lợi từ cùng một cơ sở hạ tầng caching như pages. ```typescript // nuxt.config.ts 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 } } }) ``` Để invalidate cache động, sử dụng wrapper `defineCachedEventHandler`: ```typescript // server/api/trending.get.ts 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' } }) ``` ## Xử lý Error và Định dạng Response Các error response nhất quán cải thiện khả năng sử dụng API. Tạo một utility error handler dùng chung: ```typescript // server/utils/errors.ts 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' }) } ``` Để tìm hiểu toàn diện về các pattern Vue.js và state management, hãy khám phá bài viết [so sánh Pinia vs Vuex](/blog/vue-nuxt/vue-3-pinia-vs-vuex-state-management). > **Checklist Production** > > Trước khi triển khai Nitro servers: validate environment variables với Zod schemas, implement rate limiting middleware, thêm request logging để debugging, và cấu hình CORS headers cho truy cập API cross-origin. ## Triển khai Đa Nền tảng Hệ thống preset của Nitro tạo ra các build được tối ưu hóa cho từng platform: ```typescript // nuxt.config.ts 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'] } } }) ``` Đối với triển khai Node.js, output bao gồm một server standalone: ```bash # Build for production npm run build # Start the server node .output/server/index.mjs ``` > **Nuxt 3 End of Life** > > Nuxt 3 đạt end-of-life vào ngày 31 tháng 7 năm 2026. Các dự án nên migrate sang Nuxt 4 sử dụng [hướng dẫn migration chính thức](https://nuxt.com/docs/getting-started/upgrade). Nuxt 5 với Nitro v3 sẽ theo sau ngay sau đó. ## Kết luận - Server routes trong `server/api/` tự động ánh xạ tới các endpoint `/api/*` với hậu tố HTTP method (`.get.ts`, `.post.ts`) kiểm soát loại request - Middleware trong `server/middleware/` xử lý authentication, logging và biến đổi request trước khi routes thực thi - Đối tượng `event.context` chia sẻ dữ liệu có type giữa middleware và handlers trong một request - Server utils trong `server/utils/` tự động import xuyên suốt server code, lý tưởng cho database clients và logic dùng chung - Nuxt 4 áp dụng đặt tên Web API (`status`/`statusText`) để chuẩn bị cho Nitro v3 - `defineCachedEventHandler` cung cấp caching cấp route với các điều khiển invalidation - Preset Nitro cho phép triển khai không cần cấu hình tới Vercel, Netlify, Cloudflare và server Node.js --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/vi/blog/vue-nuxt/nuxt-nitro-server-routes-2026