# Nuxt Nitro และ Server Routes ในปี 2026: Full-Stack Vue และ API Endpoints > เรียนรู้การใช้งาน Nuxt Nitro server routes เพื่อสร้างแอปพลิเคชัน Vue แบบ full-stack บทความครอบคลุม API endpoints, middleware, การเชื่อมต่อฐานข้อมูล และการ deploy production ด้วย 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 เปลี่ยนแอปพลิเคชัน Vue ให้กลายเป็นแพลตฟอร์ม full-stack ที่ทรงพลังโดยการมอบ server engine ที่ทำงานได้หลายแพลตฟอร์มซึ่งจัดการ API routes, middleware และ server-side logic ควบคู่ไปกับ frontend components ด้วย Nuxt 4.3 และ Nitro v3 ที่กำลังจะมาถึง การสร้าง backend ที่พร้อมสำหรับ production ไม่เคยผสานรวมกับการพัฒนา Vue ได้ดีเท่านี้มาก่อน > **Full-Stack ใน Repository เดียว** > > Nitro ช่วยให้สามารถแชร์ TypeScript types ระหว่าง frontend และ backend ลดความแตกต่างของ API contract และลด boilerplate Server routes อยู่ใน `server/api/` และพร้อมใช้งานอัตโนมัติที่ endpoint `/api/*` ## ทำความเข้าใจสถาปัตยกรรม Nuxt Nitro Server Engine Nitro ทำหน้าที่เป็น JavaScript server runtime แบบ universal ที่ขับเคลื่อน server directory ของ Nuxt แตกต่างจาก Node.js server แบบดั้งเดิม Nitro จะคอมไพล์เป็น bundle ที่ปรับแต่งสำหรับแต่ละแพลตฟอร์มและสามารถ deploy ได้อย่างราบรื่นไปยัง [Vercel](https://vercel.com/docs/frameworks/nuxt), [Netlify](https://docs.netlify.com/frameworks/nuxt/), Cloudflare Workers และสภาพแวดล้อม Node.js มาตรฐานโดยไม่ต้องเปลี่ยนแปลงโค้ด สถาปัตยกรรมแยก concerns ผ่านข้อตกลงของ directory: ```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 สแกนสี่ directories: `server/api` สำหรับ API routes พร้อม prefix `/api`, `server/routes` สำหรับ routes ที่ไม่มี prefix, `server/middleware` สำหรับ request interceptors และ `server/utils` สำหรับ server utilities ที่ใช้ร่วมกัน ไฟล์นอกเหนือจาก directories เหล่านี้จะไม่ถูกมองเห็นโดย server runtime ## สร้าง RESTful API Endpoints ด้วย defineEventHandler Server routes ปฏิบัติตามข้อตกลง file-based routing โดยชื่อไฟล์จะถูก map โดยตรงไปยัง URL paths ส่วนต่อท้าย HTTP method ควบคุมว่า request ใดที่แต่ละ handler จะรับ ```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 นำข้อตกลงการตั้งชื่อ Web API มาใช้เพื่อเตรียมพร้อมสำหรับ Nitro v3 Property `statusCode` กลายเป็น `status` และ `statusMessage` กลายเป็น `statusText` แม้ว่า properties เดิมจะยังคงทำงานได้ แต่การย้ายไปใช้การตั้งชื่อใหม่จะช่วยให้เข้ากันได้กับ Nuxt 5 การจัดการ POST requests พร้อมการ validate 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 สำหรับ Authentication และ Logging ไฟล์ middleware จะถูกเรียกใช้งานก่อน route handlers เปิดใช้งาน cross-cutting concerns เช่น authentication, logging และการแปลง request แตกต่างจาก route handlers middleware จะไม่ส่งคืน response โดยตรง ```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' }) } }) ``` object `event.context` คงอยู่ตลอด middleware และ handlers ภายใน request เดียว มอบวิธีที่ type-safe ในการแชร์ข้อมูล กำหนด context types ในไฟล์ declaration: ```typescript // server/types/context.d.ts declare module 'h3' { interface H3EventContext { user?: { id: string email: string role: 'admin' | 'user' } } } ``` สำหรับการเตรียมตัวสัมภาษณ์เกี่ยวกับแนวคิด Nuxt server สามารถศึกษาโมดูล [คำถามสัมภาษณ์ Nuxt Server Routes](/technologies/vue-nuxt/interview-questions/nuxt-server-routes) ## การเชื่อมต่อ Database ด้วย Prisma และ Server Utils Server utilities ใน `server/utils/` จะถูก auto-import ทั่วทั้ง server code ทำให้ database clients และ logic ที่ใช้ร่วมกันสามารถเข้าถึงได้โดยไม่ต้อง import อย่างชัดเจน ```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 } ``` ด้วย database client ที่พร้อมใช้งานแบบ global route handlers สามารถเข้าถึงได้โดยตรง: ```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 สำหรับ Runtime Initialization Server plugins ใน `server/plugins/` จะถูกเรียกใช้งานครั้งเดียวเมื่อ server เริ่มทำงาน เหมาะสำหรับการเริ่มต้นการเชื่อมต่อ การตั้งเวลา tasks หรือการตั้งค่า 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') }) }) ``` ระบบ plugin ผสานรวมกับ [Nitro hooks](https://nitro.unjs.io/guide/plugins) สำหรับการจัดการ lifecycle Hooks จะถูกเรียกใช้ที่จุดเฉพาะ: `request` ก่อนการจัดการ, `beforeResponse` ก่อนการส่ง และ `close` ระหว่าง shutdown ## การเรียก API แบบ Type-Safe จาก Vue Components Utility `$fetch` ของ Nuxt มอบ type inference จาก server routes เมื่อใช้ alias `~/server` เมื่อรวมกับ [composable useFetch](/technologies/vue-nuxt/interview-questions/nuxt-data-fetching) components สามารถใช้งาน APIs พร้อมการสนับสนุน TypeScript เต็มรูปแบบ ```vue ``` ## กลยุทธ์ Caching สำหรับ Server Routes Nuxt 4.3 นำเสนอการควบคุม caching ที่ปรับปรุงแล้วผ่าน `routeRules` ใน `nuxt.config.ts` Server routes ได้รับประโยชน์จากโครงสร้างพื้นฐาน caching เดียวกันกับ 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 แบบ dynamic ใช้ 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' } }) ``` ## การจัดการ Error และการจัดรูปแบบ Response Error responses ที่สอดคล้องกันช่วยปรับปรุงความสามารถในการใช้งาน API สร้าง utility error handler ที่ใช้ร่วมกัน: ```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' }) } ``` สำหรับ patterns Vue.js และ state management แบบครอบคลุม สามารถศึกษาบทความ [การเปรียบเทียบ Pinia vs Vuex](/blog/vue-nuxt/vue-3-pinia-vs-vuex-state-management) > **Checklist สำหรับ Production** > > ก่อน deploy Nitro servers: validate environment variables ด้วย Zod schemas, implement rate limiting middleware, เพิ่ม request logging สำหรับ debugging และกำหนดค่า CORS headers สำหรับการเข้าถึง API แบบ cross-origin ## การ Deploy ข้ามแพลตฟอร์ม ระบบ preset ของ Nitro สร้าง builds ที่ปรับแต่งสำหรับแต่ละแพลตฟอร์ม: ```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'] } } }) ``` สำหรับการ deploy บน Node.js output จะรวม server แบบ standalone: ```bash # Build for production npm run build # Start the server node .output/server/index.mjs ``` > **Nuxt 3 สิ้นสุดการสนับสนุน** > > Nuxt 3 จะสิ้นสุดการสนับสนุนในวันที่ 31 กรกฎาคม 2026 โปรเจกต์ควรย้ายไปยัง Nuxt 4 โดยใช้ [คู่มือการย้ายอย่างเป็นทางการ](https://nuxt.com/docs/getting-started/upgrade) Nuxt 5 พร้อม Nitro v3 จะตามมาในเร็วๆ นี้ ## สรุป - Server routes ใน `server/api/` จะถูก map โดยอัตโนมัติไปยัง endpoint `/api/*` โดยส่วนต่อท้าย HTTP method (`.get.ts`, `.post.ts`) ควบคุมประเภท request - Middleware ใน `server/middleware/` จัดการ authentication, logging และการแปลง request ก่อนที่ routes จะทำงาน - object `event.context` แชร์ข้อมูลที่มี type ระหว่าง middleware และ handlers ภายใน request - Server utils ใน `server/utils/` จะถูก auto-import ทั่วทั้ง server code เหมาะสำหรับ database clients และ logic ที่ใช้ร่วมกัน - Nuxt 4 นำการตั้งชื่อ Web API มาใช้ (`status`/`statusText`) เพื่อเตรียมพร้อมสำหรับ Nitro v3 - `defineCachedEventHandler` มอบ caching ระดับ route พร้อมการควบคุม invalidation - Presets ของ Nitro ช่วยให้สามารถ deploy โดยไม่ต้องกำหนดค่าไปยัง Vercel, Netlify, Cloudflare และ Node.js servers --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/vue-nuxt/nuxt-nitro-server-routes-2026