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を読んでいく#91 - #95

0
Last updated at Posted at 2025-12-18

この記事何?

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

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

91 refactor: remove default middleware

デフォルトミドルウェアを削除。req.query(), req.header(), req.param() を Hono 本体に直接実装。

変更前:

  // src/middleware/default.ts
  export const defaultMiddleware = async (c: Context, next: Function) => {
    c.req.query = (key: string) => {
      const url = new URL(c.req.url)
      return url.searchParams.get(key)
    }
    c.req.header = (name: string): string => {
      return c.req.headers.get(name)
    }
    await next()
  }

  // src/hono.ts
  middleware.push(Middleware.default)  // デフォルトミドルウェアを追加
  middleware.push(wrappedHandler)

修正

src/hono.ts:

  const result = await this.matchRoute(method, path)

  // Methods for Request object(直接 Request を拡張)
  request.param = (key: string): string => {
    if (result) {
      return result.params[key]
    }
  }

  request.header = (name: string): string => {
    return request.headers.get(name)
  }

  request.query = (key: string): string => {
    const url = new URL(c.req.url)
    return url.searchParams.get(key)
  }

  // ミドルウェアチェーンの構築
  -middleware.push(Middleware.default)  // ← 削除
  middleware.push(wrappedHandler)

src/middleware/default.ts:

ファイル自体を削除

92 Close

93 feat: auto set statusText

HTTP ステータスコードに対応する statusText を自動設定。c.status(404) を呼ぶだけで "Not Found" が設定される。

変更内容

  1. http-status.ts の追加

src/utils/http-status.ts:

  export const getStatusText = (statusNumber: number): string => {
    const text = statuses[statusNumber]
    return text
  }

  const statuses: { [key: number]: string } = {
    200: 'OK',
    201: 'Created',
    202: 'Accepted',
    204: 'No Content',
    206: 'Partial Content',
    301: 'Moved Permanently',
    302: 'Moved Temporarily',
    303: 'See Other',
    304: 'Not Modified',
    307: 'Temporary Redirect',
    308: 'Permanent Redirect',
    400: 'Bad Request',
    401: 'Unauthorized',
    402: 'Payment Required',
    403: 'Forbidden',
    404: 'Not Found',
    405: 'Not Allowed',
    406: 'Not Acceptable',
    408: 'Request Time-out',
    409: 'Conflict',
    410: 'Gone',
    411: 'Length Required',
    412: 'Precondition Failed',
    413: 'Request Entity Too Large',
    414: 'Request-URI Too Large',
    415: 'Unsupported Media Type',
    416: 'Requested Range Not Satisfiable',
    421: 'Misdirected Request',
    429: 'Too Many Requests',
    500: 'Internal Server Error',
    501: 'Not Implemented',
    502: 'Bad Gateway',
    503: 'Service Temporarily Unavailable',
    504: 'Gateway Time-out',
    505: 'HTTP Version Not Supported',
    507: 'Insufficient Storage',
  }
  1. c.status() の改善

src/context.ts:

  import { getStatusText } from './utils/http-status'

  status(number: number): void {
  +  // 既に c.res が設定されている場合は警告
  +  if (this.res) {
  +    console.warn('c.res.status is already setted.')
  +    return
  +  }
    this._status = number
  +  this._statusText = getStatusText(number)  // ← 自動で設定
  }

  -// statusText メソッドを削除(自動設定されるため不要)
  -statusText(text: string): void {
  -  this._statusText = text
  -}
  1. Data 型の定義

src/context.ts:

  +type Data = string | ArrayBuffer | ReadableStream

  export class Context {
    // ...

  -  newResponse(data: any, init: ResponseInit = {}): Response {
  +  newResponse(data: Data, init: ResponseInit = {}): Response {
      // ...
    }

  -  body(data: any, status: number = this._status, headers: Headers = this._headers): Response {
  +  body(data: Data, status: number = this._status, headers: Headers = this._headers): Response {
      // ...
    }
  }

使い方

変更前:

  app.get('/not-found', (c) => {
    c.status(404)
    c.statusText('Not Found')  // ← 手動で設定
    return c.text('Page not found')
  })

変更後:

  app.get('/not-found', (c) => {
    c.status(404)  // statusText は自動で 'Not Found' に設定される
    return c.text('Page not found')
  })

レスポンス:

  HTTP/1.1 404 Not Found
  Content-Type: text/plain; charset=UTF-8

  Page not found

知ってるようで使ってない機能たくさんあるわ....自前で返してた....

#94 feat: check response type

ハンドラーの戻り値が Response オブジェクトかチェック。型安全性を向上。

変更内容

  1. Response 型チェックの追加

src/hono.ts:

  const wrappedHandler = async (context: Context, next: Function) => {
  -  context.res = await handler(context)
  +  const res = await handler(context)
  +  if (!(res instanceof Response)) {
  +    throw new TypeError('response must be a instace of Response')
  +  }
  +  context.res = res
    await next()
  }

など、細々した型定義の修正などで正直よくわからん....

#95 Flamework to Framework

README のタイポ修正

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?