ルーティング
Hono のルーティングは柔軟で直感的です。 使い方を見てみましょう。
基本
ts
// 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 /'))
app.query('/', (c) => c.text('QUERY /'))
// 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')
)パスパラメーター
ts
app.get('/user/:name', async (c) => {
const name = c.req.param('name')
// ...
})すべてのパラメーターを一度に取得することもできます。
ts
app.get('/posts/:id/comment/:comment_id', async (c) => {
const { id, comment_id } = c.req.param()
// ...
})任意のパラメーター
ts
// Will match `/api/animal` and `/api/animal/:type`
app.get('/api/animal/:type?', (c) => c.text('Animal!'))正規表現
ts
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', async (c) => {
const { date, title } = c.req.param()
// ...
})スラッシュを含むパス
ts
app.get('/posts/:filename{.+\\.png}', async (c) => {
//...
})メソッドチェーンによるルート定義
ts
app
.get('/endpoint', (c) => {
return c.text('GET /endpoint')
})
.post((c) => {
return c.text('POST /endpoint')
})
.delete((c) => {
return c.text('DELETE /endpoint')
})グループ化
Hono インスタンスでルートをグループ化し、route メソッドでメインアプリに追加できます。
ts
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)ベースパスを変更しないグループ化
ベースパスを維持しながら、複数のインスタンスをグループ化することもできます。
ts
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ベースパス
ベースパスを指定できます。
ts
const api = new Hono().basePath('/api')
api.get('/book', (c) => c.text('List Books')) // GET /api/bookホスト名によるルーティング
ホスト名を含むルーティングにも対応しています。
ts
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'))host ヘッダーの値によるルーティング
Hono のコンストラクターで getPath() 関数を設定すると、host ヘッダーの値を使ってルーティングできます。
ts
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' },
// })この方法を応用すると、たとえば User-Agent ヘッダーに応じてルーティングを変更できます。
ルーティングの優先順位
ハンドラーやミドルウェアは登録順に実行されます。
ts
app.get('/book/a', (c) => c.text('a')) // a
app.get('/book/:slug', (c) => c.text('common')) // commonGET /book/a ---> `a`
GET /book/b ---> `common`ハンドラーが実行されると、処理は停止します。
ts
app.get('*', (c) => c.text('common')) // common
app.get('/foo', (c) => c.text('foo')) // fooGET /foo ---> `common` // foo will not be dispatched実行したいミドルウェアがある場合は、そのコードをハンドラーより前に記述してください。
ts
app.use(logger())
app.get('/foo', (c) => c.text('foo'))「フォールバック」ハンドラーを用意する場合は、ほかのハンドラーより後に記述してください。
ts
app.get('/bar', (c) => c.text('bar')) // bar
app.get('*', (c) => c.text('fallback')) // fallbackGET /bar ---> `bar`
GET /foo ---> `fallback`グループ化の順序
ルートのグループ化における順序の誤りは気づきにくいため、注意してください。 route() 関数は、第二引数(three や two など)に登録済みのルートを取り出し、自身(two や app)のルートに追加します。
ts
three.get('/hi', (c) => c.text('hi'))
two.route('/three', three)
app.route('/two', two)
export default appこの場合は、ステータスコード 200 のレスポンスを返します。
GET /two/three/hi ---> `hi`しかし、順序が間違っていると 404 を返します。
ts
three.get('/hi', (c) => c.text('hi'))
app.route('/two', two) // `two` does not have routes
two.route('/three', three)
export default appGET /two/three/hi ---> 404 Not Found