new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Hono · all subjects

routing

73 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

hono/quick preset use cases

The 'hono/quick' preset is designed for environments where the application is initialized for every request.

hono preset use cases and platforms

The 'hono' preset is highly recommended for most use cases. Although registration phase may be slower than hono/quick, it exhibits high performance once booted. It is ideal for long-life servers built with Deno, Bun, or Node.js. It is also suitable for Fastly Compute (where route registration occurs during app build phase) and environments utilizing v8 isolates such as Cloudflare Workers and Deno Deploy (where isolations persist for a certain amount of time after booting).

hono/tiny preset router configuration

The 'hono/tiny' preset uses a PatternRouter. Import: import { Hono } from 'hono/tiny'

hono/quick preset router configuration

The 'hono/quick' preset uses a SmartRouter with two routers: LinearRouter and TrieRouter. Import: import { Hono } from 'hono/quick'

hono preset router configuration

The 'hono' preset uses a SmartRouter with two routers: RegExpRouter and TrieRouter. Import: import { Hono } from 'hono'

Hono presets overview

Hono provides three presets for importing the Hono class with different router configurations. Presets are provided for common use cases so you don't have to specify the router each time. The Hono class imported from all presets is the same, with the only difference being the router.

hono/tiny preset use cases

The 'hono/tiny' preset is the smallest router package and is suitable for environments where resources are limited.

Hono router based on Trie trees and RegExpRouter

Hono's router implementation uses both Trie tree concepts and a RegExpRouter approach, designed for fast routing performance.

LinearRouter for high-frequency initialization

LinearRouter is optimized for 'one shot' situations where routes are registered frequently, such as environments that initialize with every request. Route registration is significantly faster than RegExpRouter because it adds routes without compiling strings and uses a linear approach. According to benchmarks for GET /user/lookup/username/hey, LinearRouter is 2.1x faster than KoaTreeRouter, 2.45x faster than MedleyRouter, 3.21x faster than TrekRouter, and 33.24x faster than FindMyWay.

PatternRouter for minimal bundle size

PatternRouter is the smallest router among Hono's routers and is designed for environments with limited resources. An application using only PatternRouter has a bundle size under 15KB, with example deployment sizes of 14.68 KiB total upload or 5.38 KiB gzipped.

SmartRouter default configuration code

Hono's default router configuration uses SmartRouter with RegExpRouter and TrieRouter: readonly defaultRouter: Router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()], })

RegExpRouter overview and performance

RegExpRouter is the fastest router in JavaScript. Unlike Express-style implementations using path-to-regexp, it converts route patterns into one large regular expression and performs matching in a single pass rather than using linear loops. This approach performs better than tree-based algorithms like radix-tree in most cases. However, RegExpRouter does not support all routing patterns, so it is typically used in combination with other routers that support all patterns.

TrieRouter algorithm and performance

TrieRouter is a router that uses the Trie-tree algorithm and does not use linear loops. It is not as fast as RegExpRouter but is significantly faster than the Express router. TrieRouter supports all routing patterns.

SmartRouter automatic selection

SmartRouter is useful when using multiple routers as it automatically selects the best router by inferring from the registered routers. Hono uses SmartRouter as its default router, combining RegExpRouter and TrieRouter. When the application starts, SmartRouter detects the fastest router based on routing patterns and continues to use it for the application lifecycle.

app.route() for API sub-routing

Use app.route(path, subApp) to mount a sub-application at a given path. This allows organizing API endpoints into separate Hono instances and mounting them under a base path. Example: app.route('/api', api) mounts the api app under the /api prefix.

Basic GET endpoint returning JSON

Create a GET endpoint that returns JSON using app.get(path, handler). The handler receives a context object c and returns c.json(data). Example: app.get('/hello', (c) => { return c.json({ message: 'Hello!' }) }).

Basic POST endpoint with form validation

Create a POST endpoint that accepts form data by chaining zValidator before the handler. Example: app.post('/todo', zValidator('form', schema), (c) => { const todo = c.req.valid('form'); return c.json(result) }).

Azure Functions default route prefix

By default, Azure Functions has a route prefix of /api. To change this, add the property extensions.http.routePrefix set to an empty string in the host.json file.

Handle DELETE requests

Use `app.delete('/path', (c) => ...)` to handle DELETE requests.

Handle POST requests

Use `app.post('/path', (c) => ...)` to handle POST requests.

Handler definition

A Handler is the primitive that returns a Response object.

Cloudflare Pages middleware using handleMiddleware

To use Hono middleware in Cloudflare Pages' own middleware system, export a handleMiddleware-wrapped middleware from 'functions/_middleware.ts'. Import handleMiddleware from 'hono/cloudflare-pages' and pass a Hono middleware function to it. Multiple middleware can be passed as an array.

Basic Auth middleware on Cloudflare Pages

To add Basic Authentication to Cloudflare Pages, use Hono's built-in basicAuth middleware with handleMiddleware: export const onRequest = handleMiddleware(basicAuth({ username: 'hono', password: 'acoolproject' }))

handleMiddleware function signature

handleMiddleware accepts an async function with signature (c, next) => Promise<void>, where c is the Hono context and next() continues to the next middleware. Export the result as onRequest from 'functions/_middleware.ts'.

Multiple middleware in Cloudflare Pages

To apply multiple Hono middleware in Cloudflare Pages, export onRequest as an array of handleMiddleware-wrapped middleware: export const onRequest = [handleMiddleware(middleware1), handleMiddleware(middleware2), handleMiddleware(middleware3)]

Router benchmark test scenarios

Hono's router benchmarks tested seven request scenarios: short static route (/user), static with same radix (/user/comments), dynamic route (/user/lookup/username/hey), mixed static dynamic (/event/abcd1234/comments), POST request (/event/abcd1234/comment), long static route (/very/deeply/nested/route/hello/there), and wildcard route (/static/index.html).

Router benchmark test routes

Hono's router benchmarks used 12 test routes: GET /user, GET /user/comments, GET /user/avatar, GET /user/lookup/username/:username, GET /user/lookup/email/:address, GET /event/:id, GET /event/:id/comments, POST /event/:id/comment, GET /map/:location/events, GET /status, GET /very/deeply/nested/route/hello/there, and GET /static/*. These routes represent real-world routing patterns.

Example: basePath on Hono instance

import { Hono } from 'hono' const api = new Hono().basePath('/api') api.get('/book', (c) => c.text('List Books')) // GET /api/book

Example: routing with host header

import { Hono } from 'hono' const app = new Hono({ getPath: (req) => '/' + req.headers.get('host') + req.url.replace(/^https?:\/\/[^/]+(\/[^?]*).*/, '$1'), }) app.get('/www1.example.com/hello', (c) => c.text('hello www1')) // Matches request: // new Request('http://www1.example.com/hello', { // headers: { host: 'www1.example.com' }, // })

Example: routing priority

import { Hono } from 'hono' const app = new Hono() app.get('/book/a', (c) => c.text('a')) app.get('/book/:slug', (c) => c.text('common')) // GET /book/a ---> 'a' (matches first) // GET /book/b ---> 'common' (matches second route)

Example: wildcard as fallback

import { Hono } from 'hono' const app = new Hono() app.get('/bar', (c) => c.text('bar')) app.get('*', (c) => c.text('fallback')) // GET /bar ---> 'bar' // GET /foo ---> 'fallback'

Pitfall: wildcard handler before specific routes

If a wildcard handler is registered before specific route handlers, the wildcard will match first and prevent the specific handlers from being executed. For example, app.get('*', ...) followed by app.get('/foo', ...) means /foo will be handled by the wildcard handler, not the specific /foo handler.

Pitfall: incorrect route grouping order

When using app.route() to add grouped Hono instances, the order matters. If a parent instance adds a child instance before that child has its routes configured, the routes will not be found. Routes must be configured on the child instance before the parent adds it, or the parent must add the child after its configuration is complete.

Middleware execution order

Middleware registered with app.use() executes in registration order and should be registered before route handlers to ensure they process requests before handlers.

HTTP methods supported by Hono

Hono supports the HTTP methods: GET, POST, PUT, DELETE, QUERY. These are used as methods on the Hono app instance, e.g., app.get(), app.post(), app.put(), app.delete(), app.query().

app.all() matches any HTTP method

The app.all() method matches any HTTP method for a given path. For example, app.all('/hello', (c) => c.text('Any Method /hello')) will handle requests with any HTTP method to /hello.

Custom HTTP method with app.on()

Custom HTTP methods can be registered using app.on() with the method name as a string. For example, app.on('PURGE', '/cache', (c) => c.text('PURGE Method /cache')) registers a handler for the PURGE method.

Multiple methods with app.on()

Multiple HTTP methods can be registered to a single path using app.on() with an array of method names. For example, app.on(['PUT', 'DELETE'], '/post', (c) => c.text('PUT or DELETE /post')) registers handlers for both PUT and DELETE methods.

Multiple paths with app.on()

Multiple paths can be registered to a single handler using app.on() with an array of paths. For example, app.on('GET', ['/hello', '/ja/hello', '/en/hello'], (c) => c.text('Hello')) registers the same handler for three different paths.

Wildcard path matching

Paths can include wildcard segments using * syntax. For example, app.get('/wild/*/card', ...) will match /wild/anything/card.

Path parameter with c.req.param()

Path parameters are defined using a colon prefix in the path, e.g., /user/:name. They are retrieved using c.req.param('name') to get a single parameter or c.req.param() to get all parameters as an object.

Optional path parameter with ?

Path parameters can be made optional by appending ? to the parameter name. For example, app.get('/api/animal/:type?', ...) will match both /api/animal and /api/animal/:type.

Regular expression in path parameters

Path parameters can include regular expressions in curly braces to constrain matching. For example, app.get('/post/:date{[0-9]+}/:title{[a-z]+}', ...) uses regex patterns to match digits for date and lowercase letters for title.

Path parameters matching slashes

Path parameters can be configured to match slashes using regex patterns. For example, app.get('/posts/:filename{.+\\.png}', ...) can match filenames that include slashes.

Chained route methods

Multiple HTTP method handlers for the same path can be chained together. For example, app.get('/endpoint', ...).post(...).delete(...) chains GET, POST, and DELETE handlers for /endpoint.

Grouping routes with app.route()

Routes can be grouped by creating separate Hono instances and adding them to the main app using app.route(basePath, honoInstance). For example, app.route('/book', book) adds all routes from the book instance with /book prepended to their paths.

Grouping without changing base with basePath()

Multiple Hono instances can be grouped while maintaining their original base paths using the basePath() method. Routes are added with app.route('/', instance) to preserve full paths. For example, a user instance created with new Hono().basePath('/user') will handle routes starting with /user when added with app.route('/', user).

basePath() method for setting base path

The basePath() method on a Hono instance sets a base path prefix for all routes. For example, new Hono().basePath('/api') makes a route at /book accessible as /api/book.

Routing with hostname in getPath

Custom routing logic based on hostname can be implemented by setting a custom getPath() function in the Hono constructor. For example, getPath: (req) => req.url.replace(/^https?:\/([^?]+).*$/, '$1') can parse the hostname from the URL.

Routing with host header using getPath

The host header value can be used for routing by setting a custom getPath() function that prepends the host header value to the path. This allows routing based on which host the request was sent to.

Routing priority follows registration order

Handlers and middleware are executed in the order they are registered. When a handler matches and executes, subsequent matching handlers are not executed. Specific routes should be registered before generic routes to ensure they are matched first.

Wildcard handler blocks subsequent handlers

If a wildcard handler (e.g., app.get('*', ...)) is registered before a specific handler, the wildcard will match first and the specific handler will not be executed. Place wildcard handlers after specific handlers to use them as fallbacks.

Fallback handler with wildcard

A fallback handler can be implemented by registering a wildcard handler (e.g., app.get('*', ...)) after all specific route handlers. This will match any path not matched by previous handlers.

Route grouping order matters

When using app.route() to add grouped routes, the order matters. Routes must be added to instances in the correct order so that the complete routing chain is established before the parent app uses them. If a parent app adds a grouped instance before that instance has its child routes configured, the routes will not be found.

Example: basic HTTP methods and wildcard routing

import { Hono } from 'hono' const app = new Hono() app.get('/', (c) => c.text('GET /')) app.post('/', (c) => c.text('POST /')) app.put('/', (c) => c.text('PUT /')) app.delete('/', (c) => c.text('DELETE /')) app.query('/', (c) => c.text('QUERY /')) app.get('/wild/*/card', (c) => { return c.text('GET /wild/*/card') }) app.all('/hello', (c) => c.text('Any Method /hello')) app.on('PURGE', '/cache', (c) => c.text('PURGE Method /cache')) app.on(['PUT', 'DELETE'], '/post', (c) => c.text('PUT or DELETE /post') ) app.on('GET', ['/hello', '/ja/hello', '/en/hello'], (c) => c.text('Hello') )

Example: path parameters

import { Hono } from 'hono' const app = new Hono() app.get('/user/:name', async (c) => { const name = c.req.param('name') // ... }) app.get('/posts/:id/comment/:comment_id', async (c) => { const { id, comment_id } = c.req.param() // ... })

Example: optional and regex parameters

import { Hono } from 'hono' const app = new Hono() app.get('/api/animal/:type?', (c) => c.text('Animal!')) app.get('/post/:date{[0-9]+}/:title{[a-z]+}', async (c) => { const { date, title } = c.req.param() // ... }) app.get('/posts/:filename{.+\\.png}', async (c) => { // ... })

Example: chained routes

import { Hono } from 'hono' const app = new Hono() app .get('/endpoint', (c) => { return c.text('GET /endpoint') }) .post((c) => { return c.text('POST /endpoint') }) .delete((c) => { return c.text('DELETE /endpoint') })

Example: grouping routes with app.route()

import { Hono } from 'hono' const book = new Hono() book.get('/', (c) => c.text('List Books')) // GET /book book.get('/:id', (c) => { const id = c.req.param('id') return c.text('Get Book: ' + id) }) book.post('/', (c) => c.text('Create Book')) // POST /book const app = new Hono() app.route('/book', book)

Example: grouping with basePath()

import { Hono } from 'hono' const book = new Hono() book.get('/book', (c) => c.text('List Books')) // GET /book book.post('/book', (c) => c.text('Create Book')) // POST /book const user = new Hono().basePath('/user') user.get('/', (c) => c.text('List Users')) // GET /user user.post('/', (c) => c.text('Create User')) // POST /user const app = new Hono() app.route('/', book) // Handle /book app.route('/', user) // Handle /user

Give your agent this brain