Skip to content

Hono Best Practices

 公式ドキュメントの規則に従い実行する。

Ruby on Railsモデルのような、パスとコントローラーみたいにわけてしまう書き方は避ける。

ts
// 🙁
// A RoR-like Controller
const booksList = (c: Context) => {
  return c.json('list books')
}

app.get('/books', booksList)

 複雑なジェネリックを記述しないと、コントローラーでパスパラメーターを推論することはできない。

ts
// 🙁
// A RoR-like Controller
const bookPermalink = (c: Context) => {
  const id = c.req.param('id') // Can't infer the path param
  return c.json(`get ${id}`)
}

 型を推論させるためには、パス定義の直後にハンドラーを記述する必要がある。

ts
// 😃
app.get('/books/:id', (c) => {
  const id = c.req.param('id') // Can infer the path param
  return c.json(`get ${id}`)
})

 公式のBest Practicesを参考に書いていく。

Directory Structure

.
`-- hono
    |-- src
    |   |-- handler
    |   |   |-- authors.ts
    |   |   `-- books.ts
    |   `-- index.ts
    `-- tsconfig.json

Handler

 エンドポイントによる処理を記述。***_handler.tsのような命名を好む方もいれば、ディレクトリで区切られているので、シンプルで良いという人もいると思う。

ts
// index.ts
import { Hono } from 'hono'
import authors from './handler/authors'
import books from './handler/books'

const app = new Hono()

app.route('/authors', authors)
app.route('/books', books)

export default app
ts
// authors.ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.json('list authors'))
app.post('/', (c) => c.json('create an author', 201))
app.get('/:id', (c) => c.json(`get ${c.req.param('id')}`))

export default app
ts
// books.ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.json('list books'))
app.post('/', (c) => c.json('create a book', 201))
app.get('/:id', (c) => c.json(`get ${c.req.param('id')}`))

export default app

App

 大きなアプリケーションを作成する際には、app.route()でのパスマウントが推奨されている。

ts
// index.ts
import { Hono } from 'hono'
import authors from './handler/authors'
import books from './handler/books'

const app = new Hono()

app.route('/authors', authors)
app.route('/books', books)

export default app

Other

Change Base path

 ベースパスは、変えることが可能。

ts
// index.ts
import { Hono } from 'hono'
import authors from './handler/authors'
import books from './handler/books'

const app = new Hono().basePath('/api')

app.route('/authors', authors)
app.route('/books', books)

export default app

Chained route

ts
// index.ts
import { Hono } from 'hono'
import authors from './handler/authors'
import books from './handler/books'

const app = new Hono().basePath('/api')

app.route('/authors', authors).route('/books', books)

export default app
ts
// authors.ts
import { Hono } from 'hono'

const app = new Hono()

app
  .get('/', (c) => c.json('list authors'))
  .post('/', (c) => c.json('create an author', 201))
  .get('/:id', (c) => c.json(`get ${c.req.param('id')}`))

export default app
ts
// books.ts
import { Hono } from 'hono'

const app = new Hono()

app
  .get('/', (c) => c.json('list books'))
  .post('/', (c) => c.json('create a book', 201))
  .get('/:id', (c) => c.json(`get ${c.req.param('id')}`))

export default app