跳到正文
cccskills
免费在 GitHub 公开

nuxt-server

Nuxt 5 server-side development with Nitro v3, h3 v2, API routes, middleware, and database integration. Use when creating server routes, integrating D1/Drizzle, or migrating from Nitro v2.

中文简介正在准备中。当前显示原文说明。

集成工具Cloudflare
查看安装方法

包含的文件(3)

  • SKILL.md12.3 KB
  • references/server.md13.4 KB
  • templates/server/api/blog/index.get.ts1.5 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Nuxt 5 Server Development

Server routes, API patterns, and backend development with Nitro v3.

Use when: creating server API routes, implementing server middleware, integrating databases (D1, PostgreSQL, Drizzle), handling file uploads, migrating from Nitro v2/h3 v1 to Nitro v3/h3 v2, or building backend logic.

Quick Reference

Nuxt 5 Server API Changes (from Nuxt 4)

AreaNuxt 4 (Nitro v2)Nuxt 5 (Nitro v3)
Packagenitropacknitro
h3 importsimport { ... } from 'h3'import { ... } from 'nitro/h3'
Error creationcreateError({statusCode})new HTTPError({status})
Event pathevent.pathevent.url.pathname
Event methodevent.methodevent.req.method
Status codeevent.node.res.statusCodeevent.res.status
Response headerssetResponseHeader(event, ...)event.res.headers.set(...)
Runtime configuseRuntimeConfig(event)useRuntimeConfig()
Route rules redirectstatusCodestatus

File-Based Server Routes

server/
├── api/                      # API endpoints (/api/*)
│   ├── users/
│   │   ├── index.get.ts      → GET  /api/users
│   │   ├── index.post.ts     → POST /api/users
│   │   ├── [id].get.ts       → GET  /api/users/:id
│   │   ├── [id].put.ts       → PUT  /api/users/:id
│   │   └── [id].delete.ts    → DELETE /api/users/:id
│   └── health.get.ts         → GET  /api/health
├── routes/                   # Non-API routes
│   └── sitemap.xml.get.ts    → GET  /sitemap.xml
├── middleware/               # Server middleware
├── plugins/                  # Nitro plugins
└── utils/                    # Server utilities

HTTP Method Suffixes

SuffixHTTP Method
.get.tsGET
.post.tsPOST
.put.tsPUT
.patch.tsPATCH
.delete.tsDELETE
.tsAll methods

When to Load References

Load references/server.md when:

  • Implementing complex API routes
  • Handling authentication and sessions
  • Working with cookies and headers
  • Building file upload endpoints
  • Migrating from h3 v1 to h3 v2 API

Basic Event Handler

// server/api/users/index.get.ts
export default defineEventHandler(async (event) => {
  return {
    users: [
      { id: 1, name: 'John' },
      { id: 2, name: 'Jane' }
    ]
  }
})

Web Standard Event API (v5)

Request Properties

// Nuxt 5 uses Web Standard APIs
export default defineEventHandler((event) => {
  // Path
  const path = event.url.pathname    // was: event.path
  const search = event.url.search    // URLSearchParams

  // Method
  const method = event.req.method    // was: event.method

  // Headers (Web Headers API)
  const auth = event.req.headers.get('authorization')  // was: getHeader(event, 'authorization')
  const allHeaders = event.req.headers

  return { path, search, method, auth }
})

Response Properties

export default defineEventHandler((event) => {
  // Set status
  event.res.status = 201                    // was: setResponseStatus(event, 201)

  // Set headers (Web Headers API)
  event.res.headers.set('X-Custom', 'value')     // was: setHeader(event, 'X-Custom', 'value')
  event.res.headers.append('Set-Cookie', 'val')   // was: appendResponseHeader(event, ...)

  return { message: 'Created' }
})

Legacy Helpers Still Work

The h3 v1 helper functions (auto-imported) still work for request reading:

// These continue to work (auto-imported)
const id = getRouterParam(event, 'id')
const query = getQuery(event)
const body = await readBody(event)
const cookie = getCookie(event, 'name')

But for setting responses, prefer the Web Standard API:

// Prefer v5 style
event.res.status = 201
event.res.headers.set('Cache-Control', 'max-age=3600')

// Still works but deprecated for setting
setResponseStatus(event, 201)
setHeader(event, 'Cache-Control', 'max-age=3600')

Error Handling (v5 Change)

Server-Side: HTTPError

In server routes, use HTTPError instead of createError:

// Nuxt 5 server routes
import { HTTPError } from 'nitro/h3'

export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')

  if (!id) {
    throw new HTTPError({ status: 400, statusText: 'User ID is required' })
  }

  const user = await findUser(id)

  if (!user) {
    throw new HTTPError({ status: 404, statusText: 'Not Found' })
  }

  return user
})

App-Side: createError (Unchanged)

In the Vue part of your app (app/ directory), createError continues to work:

// app/ code - createError still works
throw createError({
  statusCode: 404,
  statusMessage: 'Page Not Found',
  fatal: true
})

Validation Errors

import { z } from 'zod'
import { HTTPError } from 'nitro/h3'

const createUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.email()
})

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  const result = createUserSchema.safeParse(body)

  if (!result.success) {
    throw new HTTPError({
      status: 400,
      statusText: 'Validation failed',
    })
  }

  return { success: true, data: result.data }
})

Request Utilities

URL Parameters

// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')

  if (!id) {
    throw new HTTPError({ status: 400, statusText: 'User ID is required' })
  }

  return { id }
})

Query Parameters

export default defineEventHandler(async (event) => {
  const query = getQuery(event)

  const page = Number(query.page) || 1
  const limit = Number(query.limit) || 10
  const search = query.search as string | undefined

  return { page, limit, search }
})

Request Body

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  if (!body.name || !body.email) {
    throw new HTTPError({ status: 400, statusText: 'Name and email are required' })
  }

  return { success: true, user: { id: 1, ...body } }
})

Cookies

export default defineEventHandler(async (event) => {
  // Read cookie (helper still works)
  const sessionId = getCookie(event, 'session_id')

  // Set cookie
  setCookie(event, 'session_id', 'abc123', {
    httpOnly: true,
    secure: true,
    sameSite: 'lax',
    maxAge: 60 * 60 * 24 * 7
  })

  // Delete cookie
  deleteCookie(event, 'old_cookie')

  return { sessionId }
})

Server Middleware

// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
  const publicRoutes = ['/api/auth/login', '/api/health']

  // v5: Use event.url.pathname instead of event.path
  if (publicRoutes.includes(event.url.pathname)) {
    return
  }

  const token = event.req.headers.get('authorization')?.replace('Bearer ', '')

  if (!token) {
    throw new HTTPError({ status: 401, statusText: 'Authentication required' })
  }

  const user = await verifyToken(token)
  event.context.user = user
})

Runtime Config (v5 Change)

// Nuxt 5: useRuntimeConfig() no longer accepts event
export default defineEventHandler(() => {
  const config = useRuntimeConfig()
  return { apiBase: config.public.apiBase }
})

// Nuxt 4 (deprecated in v5):
// const config = useRuntimeConfig(event)

Database Integration

Cloudflare D1 with Drizzle

// server/utils/db.ts
import { drizzle } from 'drizzle-orm/d1'
import * as schema from '~/server/database/schema'

export function useDB(event: H3Event) {
  const { DB } = event.context.cloudflare.env
  return drizzle(DB, { schema })
}

// server/api/users/index.get.ts
export default defineEventHandler(async (event) => {
  const db = useDB(event)
  const users = await db.select().from(schema.users).limit(10)
  return { users }
})

CRUD Operations

// server/api/users/index.post.ts
import { users } from '~/server/database/schema'

export default defineEventHandler(async (event) => {
  const db = useDB(event)
  const body = await readBody(event)

  const [user] = await db.insert(users)
    .values({ name: body.name, email: body.email })
    .returning()

  return { user }
})

// server/api/users/[id].delete.ts
import { eq } from 'drizzle-orm'
import { users } from '~/server/database/schema'
import { HTTPError } from 'nitro/h3'

export default defineEventHandler(async (event) => {
  const db = useDB(event)
  const id = getRouterParam(event, 'id')

  if (!id) {
    throw new HTTPError({ status: 400, statusText: 'ID is required' })
  }

  await db.delete(users).where(eq(users.id, Number(id)))
  return { success: true }
})

File Uploads

// server/api/upload.post.ts
import { HTTPError } from 'nitro/h3'

export default defineEventHandler(async (event) => {
  const formData = await readMultipartFormData(event)

  if (!formData) {
    throw new HTTPError({ status: 400, statusText: 'No file uploaded' })
  }

  const file = formData.find(f => f.name === 'file')

  if (!file) {
    throw new HTTPError({ status: 400, statusText: 'File field is required' })
  }

  const { R2 } = event.context.cloudflare.env
  const key = `uploads/${Date.now()}-${file.filename}`
  await R2.put(key, file.data)

  return { key, filename: file.filename, type: file.type }
})

Server Utilities

// server/utils/auth.ts
import { HTTPError } from 'nitro/h3'

export function requireAuth(event: H3Event) {
  const user = event.context.user

  if (!user) {
    throw new HTTPError({ status: 401, statusText: 'Authentication required' })
  }

  return user
}

export function requireRole(event: H3Event, role: string) {
  const user = requireAuth(event)

  if (user.role !== role) {
    throw new HTTPError({ status: 403, statusText: 'Insufficient permissions' })
  }

  return user
}

Route Rules (v5 Change)

// nuxt.config.ts - redirect status property renamed
export default defineNuxtConfig({
  routeRules: {
    '/old-page': {
      redirect: { to: '/new-page', status: 302 }  // was: statusCode
    },
    '/api/**': { cors: true },
    '/blog/**': { swr: 3600 }
  }
})

Common Anti-Patterns

Using createError in Server Routes

// WRONG in v5 server routes - use HTTPError
import { createError } from 'h3'
throw createError({ statusCode: 404, statusMessage: 'Not found' })

// CORRECT in v5 server routes
import { HTTPError } from 'nitro/h3'
throw new HTTPError({ status: 404, statusText: 'Not found' })

Using event.path

// WRONG - deprecated in v5
const path = event.path

// CORRECT
const path = event.url.pathname

Using useRuntimeConfig(event)

// WRONG - no longer accepts event in v5
const config = useRuntimeConfig(event)

// CORRECT
const config = useRuntimeConfig()

Not Throwing Errors

// WRONG - Returns error as data with 200 status
if (!user) {
  return { error: 'Not found' }
}

// CORRECT - Throw error
if (!user) {
  throw new HTTPError({ status: 404, statusText: 'Not found' })
}

Troubleshooting

Import errors from 'h3':

  • Change import { ... } from 'h3' to import { ... } from 'nitro/h3'
  • Auto-imports (defineEventHandler, getQuery, readBody) continue to work

404 on API Routes:

  • Ensure file is in server/api/
  • Check method suffix matches request (.get.ts for GET)

Body is Empty:

  • Ensure await readBody(event) not readBody(event)

D1 Binding Not Found:

  • Check wrangler.toml has [[d1_databases]] configured
  • Access via event.context.cloudflare.env.DB

Related Skills

  • nuxt-core: Project setup, routing, configuration
  • nuxt-data: Composables, data fetching, state
  • nuxt-production: Performance, testing, deployment
  • cloudflare-d1: D1 database patterns

Version: 5.0.0 | Last Updated: 2026-03-30 | License: MIT

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

Secure API authentication with JWT, OAuth 2.0, API keys. Use for authentication systems, third-party integrations, service-to-service communication, or encountering token management, security headers, auth flow errors.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

Creates comprehensive API changelogs documenting breaking changes, deprecations, and migration strategies for API consumers. Use when managing API versions, communicating breaking changes, or creating upgrade guides.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

Implements standardized API error responses with proper status codes, logging, and user-friendly messages. Use when building production APIs, implementing error recovery patterns, or integrating error monitoring services.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2312026年9月28日 更新

查看 secondsky 的全部技能

报告此技能的问题