Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
266 lines
5.1 KiB
Markdown
266 lines
5.1 KiB
Markdown
---
|
|
name: server-routes
|
|
description: API routes, server middleware, and Nitro server engine in Nuxt
|
|
---
|
|
|
|
# Server Routes
|
|
|
|
Nuxt includes Nitro server engine for building full-stack applications with API routes and server middleware.
|
|
|
|
## API Routes
|
|
|
|
Create files in `server/api/` directory:
|
|
|
|
```ts
|
|
// server/api/hello.ts
|
|
export default defineEventHandler((event) => {
|
|
return { message: 'Hello World' }
|
|
})
|
|
```
|
|
|
|
Access at `/api/hello`.
|
|
|
|
### HTTP Methods
|
|
|
|
```ts
|
|
// server/api/users.get.ts - GET /api/users
|
|
export default defineEventHandler(() => {
|
|
return getUsers()
|
|
})
|
|
|
|
// server/api/users.post.ts - POST /api/users
|
|
export default defineEventHandler(async (event) => {
|
|
const body = await readBody(event)
|
|
return createUser(body)
|
|
})
|
|
|
|
// server/api/users/[id].put.ts - PUT /api/users/:id
|
|
export default defineEventHandler(async (event) => {
|
|
const id = getRouterParam(event, 'id')
|
|
const body = await readBody(event)
|
|
return updateUser(id, body)
|
|
})
|
|
|
|
// server/api/users/[id].delete.ts - DELETE /api/users/:id
|
|
export default defineEventHandler((event) => {
|
|
const id = getRouterParam(event, 'id')
|
|
return deleteUser(id)
|
|
})
|
|
```
|
|
|
|
### Route Parameters
|
|
|
|
```ts
|
|
// server/api/posts/[id].ts
|
|
export default defineEventHandler((event) => {
|
|
const id = getRouterParam(event, 'id')
|
|
return getPost(id)
|
|
})
|
|
|
|
// Catch-all: server/api/[...path].ts
|
|
export default defineEventHandler((event) => {
|
|
const path = getRouterParam(event, 'path')
|
|
return { path }
|
|
})
|
|
```
|
|
|
|
### Query Parameters
|
|
|
|
```ts
|
|
// server/api/search.ts
|
|
// GET /api/search?q=nuxt&page=1
|
|
export default defineEventHandler((event) => {
|
|
const query = getQuery(event)
|
|
// { q: 'nuxt', page: '1' }
|
|
return search(query.q, Number(query.page))
|
|
})
|
|
```
|
|
|
|
### Request Body
|
|
|
|
```ts
|
|
// server/api/submit.post.ts
|
|
export default defineEventHandler(async (event) => {
|
|
const body = await readBody(event)
|
|
// Validate and process body
|
|
return { success: true, data: body }
|
|
})
|
|
```
|
|
|
|
### Headers and Cookies
|
|
|
|
```ts
|
|
// server/api/auth.ts
|
|
export default defineEventHandler((event) => {
|
|
// Read headers
|
|
const auth = getHeader(event, 'authorization')
|
|
|
|
// Read cookies
|
|
const cookies = parseCookies(event)
|
|
const token = getCookie(event, 'token')
|
|
|
|
// Set headers
|
|
setHeader(event, 'X-Custom-Header', 'value')
|
|
|
|
// Set cookies
|
|
setCookie(event, 'token', 'new-token', {
|
|
httpOnly: true,
|
|
secure: true,
|
|
maxAge: 60 * 60 * 24, // 1 day
|
|
})
|
|
|
|
return { authenticated: !!token }
|
|
})
|
|
```
|
|
|
|
## Server Middleware
|
|
|
|
Runs on every request before routes:
|
|
|
|
```ts
|
|
// server/middleware/auth.ts
|
|
export default defineEventHandler((event) => {
|
|
const token = getCookie(event, 'token')
|
|
|
|
// Attach data to event context
|
|
event.context.user = token ? verifyToken(token) : null
|
|
})
|
|
|
|
// server/middleware/log.ts
|
|
export default defineEventHandler((event) => {
|
|
console.log(`${event.method} ${event.path}`)
|
|
})
|
|
```
|
|
|
|
Access context in routes:
|
|
|
|
```ts
|
|
// server/api/profile.ts
|
|
export default defineEventHandler((event) => {
|
|
const user = event.context.user
|
|
if (!user) {
|
|
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
|
}
|
|
return user
|
|
})
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```ts
|
|
// server/api/users/[id].ts
|
|
export default defineEventHandler((event) => {
|
|
const id = getRouterParam(event, 'id')
|
|
const user = findUser(id)
|
|
|
|
if (!user) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'User not found',
|
|
})
|
|
}
|
|
|
|
return user
|
|
})
|
|
```
|
|
|
|
## Server Utils
|
|
|
|
Auto-imported in `server/utils/`:
|
|
|
|
```ts
|
|
// server/utils/db.ts
|
|
export function useDb() {
|
|
return createDbConnection()
|
|
}
|
|
```
|
|
|
|
```ts
|
|
// server/api/users.ts
|
|
export default defineEventHandler(() => {
|
|
const db = useDb() // Auto-imported
|
|
return db.query('SELECT * FROM users')
|
|
})
|
|
```
|
|
|
|
## Server Plugins
|
|
|
|
Run once when server starts:
|
|
|
|
```ts
|
|
// server/plugins/db.ts
|
|
export default defineNitroPlugin((nitroApp) => {
|
|
// Initialize database connection
|
|
const db = createDbConnection()
|
|
|
|
// Add to context
|
|
nitroApp.hooks.hook('request', (event) => {
|
|
event.context.db = db
|
|
})
|
|
})
|
|
```
|
|
|
|
## Streaming Responses
|
|
|
|
```ts
|
|
// server/api/stream.ts
|
|
export default defineEventHandler((event) => {
|
|
setHeader(event, 'Content-Type', 'text/event-stream')
|
|
setHeader(event, 'Cache-Control', 'no-cache')
|
|
setHeader(event, 'Connection', 'keep-alive')
|
|
|
|
const stream = new ReadableStream({
|
|
async start(controller) {
|
|
for (let i = 0; i < 10; i++) {
|
|
controller.enqueue(`data: ${JSON.stringify({ count: i })}\n\n`)
|
|
await new Promise(r => setTimeout(r, 1000))
|
|
}
|
|
controller.close()
|
|
},
|
|
})
|
|
|
|
return stream
|
|
})
|
|
```
|
|
|
|
## Server Storage
|
|
|
|
Key-value storage with multiple drivers:
|
|
|
|
```ts
|
|
// server/api/cache.ts
|
|
export default defineEventHandler(async (event) => {
|
|
const storage = useStorage()
|
|
|
|
// Set value
|
|
await storage.setItem('key', { data: 'value' })
|
|
|
|
// Get value
|
|
const data = await storage.getItem('key')
|
|
|
|
return data
|
|
})
|
|
```
|
|
|
|
Configure storage drivers in `nuxt.config.ts`:
|
|
|
|
```ts
|
|
export default defineNuxtConfig({
|
|
nitro: {
|
|
storage: {
|
|
redis: {
|
|
driver: 'redis',
|
|
url: 'redis://localhost:6379',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
```
|
|
|
|
<!--
|
|
Source references:
|
|
- https://nuxt.com/docs/getting-started/server
|
|
- https://nuxt.com/docs/directory-structure/server
|
|
- https://nitro.build/guide
|
|
-->
|