# Routing Routing of Hono is flexible and intuitive. Let's take a look. ## Basic ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- // HTTP Methods app.get('/', (c) => c.text('GET /')) app.post('/', (c) => c.text('POST /')) app.put('/', (c) => c.text('PUT /')) app.delete('/', (c) => c.text('DELETE /')) // Wildcard app.get('/wild/*/card', (c) => { return c.text('GET /wild/*/card') }) // Any HTTP methods app.all('/hello', (c) => c.text('Any Method /hello')) // Custom HTTP method app.on('PURGE', '/cache', (c) => c.text('PURGE Method /cache')) // Multiple Method app.on(['PUT', 'DELETE'], '/post', (c) => c.text('PUT or DELETE /post') ) // Multiple Paths app.on('GET', ['/hello', '/ja/hello', '/en/hello'], (c) => c.text('Hello') ) ``` ## Path Parameter ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/user/:name', async (c) => { const name = c.req.param('name') // ^? // ... }) ``` or all parameters at once: ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/posts/:id/comment/:comment_id', async (c) => { const { id, comment_id } = c.req.param() // ^? // ... }) ``` ## Optional Parameter ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- // Will match `/api/animal` and `/api/animal/:type` app.get('/api/animal/:type?', (c) => c.text('Animal!')) ``` ## Regexp ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/post/:date{[0-9]+}/:title{[a-z]+}', async (c) => { const { date, title } = c.req.param() // ^? // ... }) ``` ## Including slashes ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/posts/:filename{.+\\.png}', async (c) => { //... }) ``` ## Chained route ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app .get('/endpoint', (c) => { return c.text('GET /endpoint') }) .post((c) => { return c.text('POST /endpoint') }) .delete((c) => { return c.text('DELETE /endpoint') }) ``` ## Grouping You can group the routes with the Hono instance and add them to the main app with the route method. ```ts twoslash import { Hono } from 'hono' // ---cut--- const book = new Hono() book.get('/', (c) => c.text('List Books')) // GET /book book.get('/:id', (c) => { // GET /book/:id 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) ``` ## Grouping without changing base You can also group multiple instances while keeping base. ```ts twoslash import { Hono } from 'hono' // ---cut--- 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 ``` ## Base path You can specify the base path. ```ts twoslash import { Hono } from 'hono' // ---cut--- const api = new Hono().basePath('/api') api.get('/book', (c) => c.text('List Books')) // GET /api/book ``` ## Routing with hostname It works fine if it includes a hostname. ```ts twoslash import { Hono } from 'hono' // ---cut--- const app = new Hono({ getPath: (req) => req.url.replace(/^https?:\/([^?]+).*$/, '$1'), }) app.get('/www1.example.com/hello', (c) => c.text('hello www1')) app.get('/www2.example.com/hello', (c) => c.text('hello www2')) ``` ## Routing with `host` Header value Hono can handle the `host` header value if you set the `getPath()` function in the Hono constructor. ```ts twoslash import { Hono } from 'hono' // ---cut--- 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')) // A following request will match the route: // new Request('http://www1.example.com/hello', { // headers: { host: 'www1.example.com' }, // }) ``` By applying this, for example, you can change the routing by `User-Agent` header. ## Routing priority Handlers or middleware will be executed in registration order. ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/book/a', (c) => c.text('a')) // a app.get('/book/:slug', (c) => c.text('common')) // common ``` ``` GET /book/a ---> `a` GET /book/b ---> `common` ``` When a handler is executed, the process will be stopped. ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('*', (c) => c.text('common')) // common app.get('/foo', (c) => c.text('foo')) // foo ``` ``` GET /foo ---> `common` // foo will not be dispatched ``` If you have the middleware that you want to execute, write the code above the handler. ```ts twoslash import { Hono } from 'hono' import { logger } from 'hono/logger' const app = new Hono() // ---cut--- app.use(logger()) app.get('/foo', (c) => c.text('foo')) ``` If you want to have a "_fallback_" handler, write the code below the other handler. ```ts twoslash import { Hono } from 'hono' const app = new Hono() // ---cut--- app.get('/bar', (c) => c.text('bar')) // bar app.get('*', (c) => c.text('fallback')) // fallback ``` ``` GET /bar ---> `bar` GET /foo ---> `fallback` ``` ## Grouping ordering Note that the mistake of grouping routings is hard to notice. The `route()` function takes the stored routing from the second argument (such as `three` or `two`) and adds it to its own (`two` or `app`) routing. ```ts three.get('/hi', (c) => c.text('hi')) two.route('/three', three) app.route('/two', two) export default app ``` It will return 200 response. ``` GET /two/three/hi ---> `hi` ``` However, if they are in the wrong order, it will return a 404. ```ts twoslash import { Hono } from 'hono' const app = new Hono() const two = new Hono() const three = new Hono() // ---cut--- three.get('/hi', (c) => c.text('hi')) app.route('/two', two) // `two` does not have routes two.route('/three', three) export default app ``` ``` GET /two/three/hi ---> 404 Not Found ```