Server Routes
Event handlers
An event handler is a function that will be binded to a route and executed when the route is matched by the router for an incoming request.
Filesystem routing
Nitro supports file-based routing for your API routes (files are automatically mapped to h3 routes). Defining a route is as simple as creating a file inside the api/
or routes/
directory.
You can only define one handler per files and you can append the HTTP method to the filename to define a specific request method.
api/
test.ts <-- /api/test
routes/
hello.get.ts <-- GET /hello
hello.post.ts <-- POST /hello
nitro.config.ts
You can nest routes by creating subdirectories.
routes/
communities/
index.get.ts
index.post.ts
[id]/
index.get.ts
index.post.ts
hello.get.ts
hello.post.ts
api/
directory as a feature, therefore routes placed in /api
won't work.
You will have to use routes/api/
.Simple routes
First, create a file in routes/
or api/
directory. The filename will be the route path.
Then, export a function wrapped in defineEventHandler
that will be executed when the route is matched.
export default defineEventHandler(() => {
return { hello: 'API' }
})
Route with params
Single param
To define a route with params, use the [<param>]
syntax where <param>
is the name of the param. The param will be available in the event.context.params
object or using the getRouterParam
utility from unjs/h3.
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
return `Hello ${name}!`
})
Call the route with the param /hello/nitro
, you will get:
Hello nitro!
Multiple params
You can define multiple params in a route using [<param1>]/[<param2>]
syntax where each param is a folder. You cannot define multiple params in a single filename of folder.
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
const age = getRouterParam(event, 'age')
return `Hello ${name}! You are ${age} years old.`
})
Catch all params
You can capture all the remaining parts of a URL using [...<param>]
syntax. This will include the /
in the param.
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
return `Hello ${name}!`
})
Call the route with the param /hello/nitro/is/hot
, you will get:
Hello nitro/is/hot!
Specific request method
You can append the HTTP method to the filename to force the route to be matched only for a specific HTTP request method, for example hello.get.ts
will only match for GET
requests. You can use any HTTP method you want.
// routes/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
// Do something with id
return `User profile!`
})
Catch all route
You can create a special route that will match all routes that are not matched by any other route. This is useful for creating a default route.
To create a catch all route, create a file named [...].ts
in the routes/
or api/
directory or in any subdirectory.
export default defineEventHandler(event => {
const url = getRequestURL(event)
return `Hello ${url}!`
})
Environment specific handlers
You can specify for a route that will only be included in specific builds by adding a .dev
, .prod
or .prerender
suffix to the file name, for example: routes/test.get.dev.ts
or routes/test.get.prod.ts
.
handlers[]
config.Middleware
Nitro route middleware can hook into the request lifecycle.
Middleware are auto-registered within the middleware/
directory.
routes/
hello.ts
middleware/
auth.ts
logger.ts
...
nitro.config.ts
Simple middleware
Middleware are defined exactly like route handlers with the only exception that they should not return anything. Returning from middleware behaves like returning from a request - the value will be returned as a response and further code will not be ran.
export default defineEventHandler((event) => {
// Extends or modify the event
event.context.user = { name: 'Nitro' }
})
Middleware in middleware/
directory are automatically registered for all routes. If you want to register a middleware for a specific route, see Object Syntax Event Handler.
Route Meta
You can define route handler meta at build-time using defineRouteMeta
micro in the event handler files.
defineRouteMeta({
openAPI: {
tags: ["test"],
description: "Test route description",
parameters: [{ in: "query", name: "test", required: true }],
},
});
export default defineEventHandler(() => "OK");
Execution order
Middleware are executed in directory listing order.
middleware/
auth.ts <-- First
logger.ts <-- Second
... <-- Third
Prefix middleware with a number to control their execution order.
middleware/
1.logger.ts <-- First
2.auth.ts <-- Second
3.... <-- Third
1.filename.ts
, 2.filename.ts
and 10.filename.ts
, the 10.filename.ts
will come after the 1.filename.ts
. To avoid this, prefix 1-9
with a 0
like 01
, if you have more than 10 middleware in the same directory.Request filtering
Middleware are executed on every request.
Apply custom logic to scope them to specific conditions.
For example, you can use the URL to apply a middleware to a specific route:
export default defineEventHandler((event) => {
// Will only execute for /auth route
if (getRequestURL(event).pathname.startsWith('/auth')) {
event.context.user = { name: 'Nitro' }
}
})
Error handling
You can use the utilities available in H3 to handle errors in both routes and middlewares.
The way errors are sent back to the client depends on the route's path. For most routes Content-Type
is set to text/html
by default and a simple html error page is delievered. If the route starts with /api/
(either because it is placed in api/
or routes/api/
) the default will change to application/json
and a JSON object will be sent.
This behaviour can be overridden by some request properties (e.g.: Accept
or User-Agent
headers).
Route Rules
Nitro allows you to add logic at the top-level for each route of your configuration. It can be used for redirecting, proxying, caching and adding headers to routes.
It is a map from route pattern (following unjs/radix3) to route options.
When cache
option is set, handlers matching pattern will be automatically wrapped with defineCachedEventHandler
. See the cache guide to learn more about this function.
swr: true|number
is shortcut for cache: { swr: true, maxAge: number }
You can set route rules in nitro.config.ts
using the routeRules
option.
export default defineNitroConfig({
routeRules: {
'/blog/**': { swr: true },
'/blog/**': { swr: 600 },
'/blog/**': { static: true },
'/blog/**': { cache: { /* cache options*/ } },
'/assets/**': { headers: { 'cache-control': 's-maxage=0' } },
'/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
'/old-page': { redirect: '/new-page' },
'/old-page/**': { redirect: '/new-page/**' },
'/proxy/example': { proxy: 'https://example.com' },
'/proxy/**': { proxy: '/api/**' },
}
})