API Routes
Server-side API endpoints with file-based routing powered by Nitro.
Avalon uses Nitro for server-side API routes. Routes are defined as files in the routes/ directory and automatically mapped to endpoints.
Basic route
Create a file in routes/api/ and export a default event handler:
// routes/api/hello.ts
export default defineEventHandler(() => {
return { message: 'Hello from the API' };
});
This creates a GET /api/hello endpoint that returns JSON.
Route mapping
| File | URL |
|---|---|
routes/api/hello.ts | /api/hello |
routes/api/users/index.ts | /api/users |
routes/api/users/[id].ts | /api/users/:id |
routes/api/posts/[...slug].ts | /api/posts/* |
Dynamic parameters
Access route parameters via event.context.params:
// routes/api/users/[id].ts
export default defineEventHandler((event) => {
const id = event.context.params?.id;
return { userId: id };
});
HTTP methods
Handle specific methods by exporting named handlers:
// routes/api/users.ts
export default defineEventHandler(async (event) => {
const method = event.method;
if (method === 'GET') {
return { users: [] };
}
if (method === 'POST') {
const body = await readBody(event);
return { created: body };
}
});
Reading request data
Nitro provides utilities for reading request data:
export default defineEventHandler(async (event) => {
// JSON body
const body = await readBody(event);
// Query parameters (?page=1&limit=10)
const query = getQuery(event);
// Headers
const auth = getHeader(event, 'authorization');
// Cookies
const session = getCookie(event, 'session');
return { body, query };
});
Setting response headers
export default defineEventHandler((event) => {
setHeader(event, 'Cache-Control', 'public, max-age=3600');
setResponseStatus(event, 201);
return { created: true };
});
Error responses
Use createError to return HTTP errors:
export default defineEventHandler((event) => {
const id = event.context.params?.id;
if (!id) {
throw createError({
statusCode: 400,
message: 'Missing user ID',
});
}
return { userId: id };
});
Route rules
Configure caching and other behavior per-route in your Vite config:
nitro: {
routeRules: {
'/api/**': {
headers: { 'Access-Control-Allow-Origin': '*' },
},
'/api/static-data': {
cache: { maxAge: 3600 },
},
},
}
Middleware
Create server middleware that runs before route handlers:
// routes/_middleware.ts
export default defineEventHandler((event) => {
// Runs before every route in this directory
console.log(`${event.method} ${event.path}`);
});