見出し画像

Hono のエラー設計。 ログと例外を 「最初に」 決める理由

「とりあえず console.log」 で地獄を見たこと、ありませんか?

API サーバーを作るとき、一番楽しいのは「正常系」の実装です。
データを取得して、加工して、JSON で返す。
Postman で叩いて `200 OK` が返ってきたときの快感。
わかります。

でも、リリース後に僕たちを待っているのは、容赦ない「異常系」の現実です。

「データが見つからない」
「DB 接続がタイムアウトした」
「予期せぬ入力が来た」

そんなとき、ログを見に行ったら `undefined` とだけ表示されていたり、あるいは何も出力されていなかったりして、絶望した経験はないでしょうか?

「エラーハンドリングは、最後にまとめてやればいいや」

かつての僕はそう思っていました。
しかし、断言します。
それは死亡フラグです。

ビジネスロジックを書き始める前に、まず「どう転ぶか(例外)」「どう記録するか(ログ)」を決める。
いわば「受け身の取り方」を最初に設計しておくことこそが、個人開発を長く続けるための生存戦略なのです。

今日は、軽量フレームワーク「Hono」を題材に、僕が実践している「最初に決めるべきエラー設計」についてお話しします。


なぜ 「最初に」 決める必要があるのか

理由はシンプルです。
後からエラーハンドリングを追加すると、コードがスパゲッティになるからです。

設計なしに進めると、あちこちのコントローラーで:

try {
  // 処理
} catch (e) {
  console.error(e)
  return c.json({ message: 'エラーです' }, 500)
}

こんなコードを量産することになります。
これでは、以下の問題が起きます。

📌 ログが統一されない:
`console.log`、`console.error`、あるいはライブラリのロガーが混在し、CloudWatch や Sentry で検索できない。

📌 ステータスコードが適当:
本来 `400`(クライアントのミス)であるべきエラーが、全部 `500`(サーバーエラー)で返される。

📌 詳細が消える:
`e.message` だけ返してしまい、スタックトレースや発生時のコンテキスト(ユーザー ID など)が闇に葬られる。

だからこそ、最初に「型」を作るのです。

Hono におけるエラー設計の勘所

Hono は非常にシンプルで柔軟なフレームワークですが、エラーハンドリングにおいても強力な機能を提供してくれています。
押さえるべきポイントは 2 つです。

`onError` ミドルウェアを 「最後の砦」 にする

各ルートハンドラ(`app.get` など)で `try-catch` を書くのをやめましょう。
Hono には、キャッチされなかった例外をフックできる `onError` という仕組みがあります。

ここで一元的にエラーを処理することで、個々のロジックからノイズ(エラー処理コード)を消し去ることができます。

「例外」 を共通言語にする

「ユーザーが見つからない」も「DB エラー」も、プログラム上はただの `Error` オブジェクトです。
しかし、これらを区別しなければなりません。

そこで、独自のカスタム例外クラスを作ります。
「この例外が投げられたら 404 を返す」「この例外なら 500」というルールをクラスに持たせるのです。

こうすることで、例外は「バグ」ではなく、「システムからの正規のメッセージ」へと昇華されます。

では、具体的にどう実装すればいいのか?
ここからは、僕が実際のプロダクトで使っている「カスタム例外クラス」「鉄壁の `onError` 実装」のコードを、コピペで使える形で公開します。

ここから先は

4,182字 / 1画像

メンバーシップ ¥ 500 /月

■メンバーシップ 15 年目フリーランス開発者のひとり戦略を支える作戦会議室です。\ 案件に追われる…

ベーシックプラン

¥500 / 月

最後まで読んでいただき、ありがとうございます。もしこの記事が「役に立った」「心に響いた」と感じたら、珈琲一杯分サポートいただけると嬉しいです。あなたの温かい応援を力に、また次の創作活動に励みます。