0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HonoのマージされたPRを読んでいく#16 - #20

0
Last updated at Posted at 2025-12-03

この記事何?

エンジニア歴1年半。業務で利用しているHonoが大好きだが、TSもプログラミング知識も弱々すぎて上手く使いこなせない。速いはずが多分生かせてない。
ちゃんと理解するためにソースコードリーディングしたい。

でも目的なくソースコード眺めても意味ないし……ねむい……
そうだ!PRを全部読めば、変遷やなぜ変更されているかストーリー的に分かるのでは。
と思ったのでチャレンジしてみる。PR2000以上あるので、全部できるかは知らん。
https://github.com/honojs/hono

#16 Can use async on handler

ハンドラーでasync/awaitが使えるように

変更前:
  // 同期処理のみ
  app.get('/hello', () => {
    return new Response('Hello')
  })

  // fetch などの非同期処理が使えない
  app.get('/data', () => {
    const data = fetch('https://api.example.com/data')  // Promiseが返る
    return new Response(data)  // [object Promise] になってしまう
  })

  変更後:
  // async/await が使える
  app.get('/data', async () => {
    const response = await fetch('https://api.example.com/data')
    const data = await response.json()
    return new Response(JSON.stringify(data))
  })

ミドルウェアが完全にasync/awaitベースに

変更前:
// 同期的なミドルウェア
const logger = (c, next) => {
  console.log(`[${c.req.method}] ${c.req.url}`)
  next()  // ← 同期呼び出し
}

const addHeader = (c, next) => {
  next()  // ← 先に次のハンドラーを呼ぶ
  c.res.headers.add('x-message', 'This is middleware!')
}

変更後:
// 非同期ミドルウェア
const logger = async (c, next) => {
  console.log(`[${c.req.method}] ${c.req.url}`)
  await next()  // ← 非同期呼び出し(必ずawait!)
}

const addHeader = async (c, next) => {
  await next()  // ← 次のハンドラーを待つ
  await c.res.headers.add('x-message', 'This is middleware!')
}

#17 Logger middleware

Loggerミドルウェアの追加。

新規ファイル: src/middleware/logger.js

  const logger = (fn = console.log) => {
    return async (c, next) => {
      const { method } = c.req
      const path = getPathFromURL(c.req.url)

      log(fn, LogPrefix.Incoming, method, path)

      const start = Date.now()

      try {
        await next()
      } catch (e) {
        log(fn, LogPrefix.Error, method, path, c.res.status || 500, time(start))
        throw e
      }

      log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start))
    }
  }

使い方:

  const { Hono, Middleware } = require('hono')
  const app = new Hono()

  // Logger ミドルウェアをマウント
  app.use('*', Middleware.logger())

  app.get('/', () => new Response('Hello'))

出力例:

    --> GET /
    <-- GET / 200 5ms
const LogPrefix = {
  Outgoing: '-->',
  Incoming: '<--',
  Error: 'xxx',
}

const colorStatus = (status) => {
    const out = {
      7: `\x1b[35m${status}\x1b[0m`,  // 700番台: マゼンタ(未使用)
      5: `\x1b[31m${status}\x1b[0m`,  // 500番台: 赤(サーバーエラー)
      4: `\x1b[33m${status}\x1b[0m`,  // 400番台: 黄(クライアントエラー)
      3: `\x1b[36m${status}\x1b[0m`,  // 300番台: シアン(リダイレクト)
      2: `\x1b[32m${status}\x1b[0m`,  // 200番台: 緑(成功)
      1: `\x1b[32m${status}\x1b[0m`,  // 100番台: 緑(情報)
      0: `\x1b[33m${status}\x1b[0m`,  // その他: 黄
    }
    return out[(status / 100) | 0]
  }

ログの種類(入力、出力、ステータスコードの色付け)もこうやってセッティングしているのか〜。ほえ〜。

#18 In test, use edge-mock instead of node-fetch

テストで使う依存関係をnode-fetchからedge-mockに変更

#19 Use test directory

ディレクトリ整理
https://github.com/honojs/hono/pull/19

#20

なし

PRがすごい綺麗だ〜。変更が10ファイル程度に収まっている。OSSとして育てていくの視野に入れてるとしても、個人開発でこれだけ綺麗にPR作っていくのすごい。見習いたい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?