Skip to content

Latest commit

 

History

History
290 lines (212 loc) · 8.25 KB

2.routing.md

File metadata and controls

290 lines (212 loc) · 8.25 KB
icon
ri:direction-line

Server Routes

Nitro support filesystem routing to automatically map files to h3 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.

:read-more{to="https://h3.unjs.io/guide/event"}

Filesystem routing

Nitro supports file-based routing for your API routes (file are atomatically 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

::note If you are using Nuxt, move the server/api/ and server/routes/ instead. ::

::tip Some providers like Vercel use a top-level api/ directory as a feature, therefore routes placed in /api wont 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.

::code-group

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

  // Do something with id

  return `User profile!`
})
// routes/users.post.ts
export default defineEventHandler(async event => {
  const body = await readBody(event)

  // Do something with body like saving it to a database

  return { updated: true }
})

::

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}!`
})

Middleware

Nitro route middleware can hook into the request lifecycle.

::tip A middleware can modify the request before it is processed, not after. ::

:read-more{to="https://h3.unjs.io/guide/event-handler#middleware"}

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.

::note Returning anything from a middleware will close the request and should be avoided! Any returned value from middleware will be the response and further code will not be executed however this is not recommended to do! ::

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

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' }
  }
})

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 guide cache to learn more about this function.

::note swr: true|number is shortcut for cache: { swr: true, maxAge: number } ::

You can set route rules in nitro.config.ts using the routeRules option.

::code-group

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/**' },
  }
})
export default defineNuxtConfig({
  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/**' },
  }
})

::

Object Syntax Event Handler

H3 introduces support for defining event handlers using an Object syntax. With this approach, you can define hooks that run before or after each handler, such as authentication or compression middleware.

const auth = defineRequestMiddleware((event) => {
  event.context.auth = { name: 'admin' }
})

const compression = defineResponseMiddleware((event) => {
  // Example: https://stackblitz.com/edit/github-mb6bz3
})

export default eventHandler({
  onRequest: [auth],
  onBeforeResponse: [compression],
  async handler(event) {
    return `Hello ${event.context.auth?.name || 'Guest'}`
  },
})