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` 実装」のコードを、コピペで使える形で公開します。
ここから先は
最後まで読んでいただき、ありがとうございます。もしこの記事が「役に立った」「心に響いた」と感じたら、珈琲一杯分サポートいただけると嬉しいです。あなたの温かい応援を力に、また次の創作活動に励みます。
