Routing

Adding Routes

H3 app instance has a built in router system to register routes matching patterns with parameter or specific HTTP method.

Router is powered by 🌳 rou3, an ultra-fast and tiny route matcher engine.

Example: Register a route to match requests to the /hello endpoint with HTTP GET method:

// Method 1: using app.[method]
app.get("/hello", () => "Hello world!");

// Method 2: using app.on(method)
app.on("GET", "/hello", () => "Hello world!");

You can register multiple event handlers for the same route with different methods:

app
  .get("/hello", () => "GET Hello world!")
  .post("/hello", () => "POST Hello world!");

You can also use app.all method to register a route accepting any HTTP method:

app.all("/hello", (event) => `This is a ${event.req.method} request!`);

Route Params

You can define parameters in your routes using : prefix:

app.get("/hello/:name", (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 respond Hello world!.

Instead of named params, you can use * for unnamed and optional params:

app.get("/hello/*", (event) => `Hello!`);

Catch-all param

Adding /hello/:name route will match /hello/world or /hello/123. But it will not match /hello/foo/bar.

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

app.get("/hello/**", (event) => `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.

Adding Middleware

You can register middleware handlers to app instance using the app.use.

Example: Register global middleware that calls on every route.

app.use((event) => {
  console.log(event);
});

Example: Register routed middleware that matches GET requests for specific routes starting with the prefix /blog (i.e. /blog/, /blog/world, /blog/123, etc.).

app.use(
  (event) => {
    console.log(event);
  },
  { route: "/blog/**", method: "GET" },
);

You can define multiple middleware.

app.use(() => "First");
app.use(() => "Second");

In the example above, the first event handler will be called for every request and the second one will never be called.

However, if you do not return a response from the first event handler, the second one will be called. This is useful to have a middleware pattern.

app.use((event) => {
  console.log("First");
});

app.use((event) => {
  console.log("Second");
});

If all handlers get called and no response is returned, h3 will continue with the main router handlers.

You can also register middleware with next argument to intercept return values of next middleware or handlers:

app.use(async (event, next) => {
  const rawResponse = await next();
  // [intercept response]
  return rawResponse;
});

You can also register middleware that match certain requires:

app.use(
  (event, next) => {
    console.log("[alert] POST request on /blog paths!");
  },
  {
    method: "POST",
    route: "/blog/**",
    // match: (event) => event.req.method === "POST", // Same as method: "POST"
  },
);

When adding routes, you can register middleware to run with them:

app.get("/admin", (event) => {}, [auth]);