Guide

Router

Split your application using routes.


Using h3 router allows more advanced and convenient routing system such as parameters and HTTP methods while the app instance itself only allows static prefix matching.

Internally h3 uses unjs/radix3 for route matching.

Usage

First, you need to create a router using createRouter utility and add it to app stack.

import { createApp, createRouter, defineEventHandler } from "h3";

const app = createApp();
const router = createRouter();
app.use(router);

Then, you can register a route to the router using a method where the name is the HTTP method:

router.get(
  "/hello",
  defineEventHandler((event) => {
    return "Hello world!";
  }),
);

In this example, we register a route for the GET method. This means that the event handler will be called only for GET requests for the /hello route. If you try to send a POST or a request to /hello/world, the event handler will not be called.

You can still use use to register an event handler to the router. It will be called for every HTTP methods.

This means that you can register multiple event handlers for the same route with different methods:

router
  .get(
    "/hello",
    defineEventHandler((event) => {
      return "GET Hello world!";
    }),
  )
  .post(
    "/hello",
    defineEventHandler((event) => {
      return "POST Hello world!";
    }),
  );

Route params

You can define parameters in your routes using : prefix:

router.get(
  "/hello/:name",
  defineEventHandler((event) => {
    return `Hello ${event.context.params.name}!`;
  }),
);

In this example, the name parameter will be available in the event.context.params object.

If you send a request to /hello/world, the event handler will return Hello world!.

You can use as many parameters as you want in your routes.

Wildcard matcher

Instead of named params, you can use * for unnamed

router.get(
  "/hello/*",
  defineEventHandler((event) => {
    return `Hello ${event.context.params._}!`;
  }),
);

This will match both /hello and sub routes such as /hello/world or /hello/123. But it will only match one level of sub routes.

You can access to the wildcard content using event.context.params._ where _ is a string containing the wildcard content.

If you need to match multiple levels of sub routes, you can use ** prefix:

router.get(
  "/hello/**",
  defineEventHandler((event) => {
    return `Hello ${event.context.params._}!`;
  }),
);

This will match /hello, /hello/world, /hello/123, /hello/world/123, etc.

Param _ will store the full wildcard content as a single string.

Nested Routers

You can nest routers to create a tree of routers. This is useful to split your application into multiple parts like the API and the website.

import { createApp, createRouter, defineEventHandler, useBase } from "h3";

export const app = createApp();

const websiteRouter = createRouter().get(
  "/",
  defineEventHandler((event) => {
    return "Hello world!";
  }),
);

const apiRouter = createRouter().get(
  "/hello",
  defineEventHandler((event) => {
    return "Hello API!";
  }),
);

websiteRouter.use("/api/**", useBase("/api", apiRouter.handler));

app.use(websiteRouter);

We create two routers. The first one, called websiteRouter is the main one. The second one, we create a second router called apiRouter.

Then, we connect the apiRouter to the websiteRouter using use and a wildcard to be sure that every routes starting and HTTP methods with /api will be handled by the apiRouter.

Do not forget to use .handler to get the event handler from the router.

useBase is used to add a prefix to each routes of the router. In this example, we add /api prefix to each routes of the apiRouter. So, the route /hello will be /api/hello.

Finally, we register the websiteRouter to the app instance.