HonoとAWS Lambdaを使って業務改善ツールを作った話

筆者が所属するチームで、[Hono](https://hono.dev/)を使って業務改善ツールを作った事例を紹介します。

https://hono.dev/

# 業務における課題

筆者が所属するチームでは、1分間隔で更新されるリアルタイム情報を扱っています。

このリアルタイム情報は、[AWS S3](https://aws.amazon.com/jp/s3/)を使って外部システムと連携しています。

リアルタイム情報を使った開発をする中で、以下のような課題がありました。

#### デバッグの難しさ

リアルタイムデータは、gzip形式で圧縮された状態でS3に保存されます。またデータ量も多いため、解凍したデータを確認するのが面倒でした。チーム内では、データを確認する際に以下のような手順が取られていました。

1. S3からgzipされたJSONをダウンロード
1. `gunzip`コマンドで解凍
1. vscodeで開き、ファイル内検索

検証手順が複雑なことで、属人化の問題もありました。

また、先述の通り、データは1分間隔で更新されていくため、動作確認が難しいという問題がありました。
例えば「30分に1回だけ出現するデータパターン」などもあり、実データを使った動作検証が難しくなっていました。

#### 過去データを使った検証の難しさ

リアルタイムデータについては、S3に過去ログを残しています。

しかしこの過去ログ、単純に1分に1ファイルずつ保存されていく形式のため、一定期間分のデータを使った動作確認も難しくなっていました。
例えば、「デバッグのためにあるデータのステータスが変化した時刻を知りたい」といった要求があった場合でも、S3から履歴ファイルを1つずつ手動でダウンロードし、手動で`gunzip`して…という手順が取られていました。

こうした業務における課題に対処するため、弊チームでは

1. S3に格納されたリアルタイムデータを容易に閲覧できる
1. 過去ログを時系列で表示できる

というようなツールを作成することになりました。

# 技術選定

技術選定にあたっては、以下の点を考慮しました。

- チーム内ではNode.jsがメインで使用されているため、ツールの作成においてもNode.jsを使用すること
- 本来の業務と並行してツールを作成するため、工数を短時間で済ませること
- アクセス制限をかけるため認証の機構があること
- チーム内にはフロントエンドを扱うメンバーが少ないため、フロントエンドJavaScriptの知識が無くても動作させられること
- AWS Lambda上で動作できること

以上の要件から、**バックエンド側の処理でSSRを完結させることができ、動作原理も比較的シンプルで扱いやすいフレームワークということで、Honoを採用しました**。

# 実装

具体的な実装については割愛しますが、S3のデータをAWS SDKで取得し、`hono/jsx`で表示するというシンプルな実装になっています。



```tsx
import { Hono } from "hono";

const app = new Hono();

app.get("/", async (c) => {
  const data = await getDataFromS3(); // S3からデータを取得する処理

  return c.html(
    <html>
      <head>
        ...
      </head>
      <body>
        {/* S3から取ってきたデータを表示 */}
        {data.map(d => (<div>{d}</div>))}
      </body>
    </html>
  );
});
```

上記の実装に加えて、ミドルウェアなどをいくつか使用しています。

### basic認証

まず[basic認証ミドルウェア](https://hono.dev/docs/middleware/builtin/basic-auth)です。
ツールの利用時に、ここで指定したユーザー名とパスワードを使ってログインすることを必須にできます。

https://hono.dev/docs/middleware/builtin/basic-auth

```ts
const app = new Hono();

app.use(
  basicAuth({
    username: "＜ユーザー名＞",
    password: "＜パスワード＞",
    invalidUserMessage: "Unauthorized. Please see https://github.com/... .",
  }),
);

app.get("/", async (c) => {
  ...
```

`invalidUserMessage`で認証に失敗した時のエラーメッセージをカスタマイズできます。


### hono/jsx

tsconfig.jsonに以下の設定を追記することで、honoからhtmlを返却する際に、jsxを使用できるようになります。

https://hono.dev/docs/guides/jsx

```jsonc:tsconfig.json
{
  "compilerOptions": {
    // hono向け設定
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx"
  }
}
```

```tsx:(jsx使用例)
app.get("/", async (c) => {
  return c.html(
    <html>
      ...
    </html>
  );
});
```

### zod validator

honoでは、[zod](https://zod.dev/)というライブラリと組み合わせることで、クライアントサイドから送られてくるパラメータをバリデーションできます。
zodを使うことで型安全になるだけでなく、クエリパラメータの値が間違っていた時のエラーハンドリングやエラーメッセージ返却も行ってくれます。

https://hono.dev/docs/guides/validation#zod-validator-middleware

```tsx
import { z } from "zod";
import { zValidator } from "@hono/zod-validator";

app.get(
  "/",
  // zodによるバリデーション処理
  zValidator(
    "query",
    z.object({
      foo: z.string(),
      bar: z.string(),
    })
  ),
  async (c) => {
    // バリデーション後の値を受け取る
    const { foo, bar } = c.req.valid("query");
    ...
  },
);
```

### Lambda Server

HonoをAWS Lambda上で動作させるためにHonoの[Lambda用のヘルパ](https://hono.dev/docs/getting-started/aws-lambda)を使っています。

https://hono.dev/docs/getting-started/aws-lambda

環境変数で条件分岐することで、

- ローカル実行時は[Node.js Server](https://hono.dev/docs/getting-started/nodejs)を使用してlocalhostを立ち上げ
- Lambda上ではLambda Serverを使用し、`handler`をexportすることでサーバー立ち上げ

という仕組みにしています。

```tsx
import { handle } from "hono/aws-lambda";
import { serve } from "@hono/node-server";

// lambda用のhandlerをexport
export const handler = handle(app);

// ローカル実行
if (!process.env.LAMBDA_TASK_ROOT) {
  console.log("Server running at http://localhost:8080/");
  serve({ ...app, port: 8080 });
}

```

以上のような仕組みを用いて、S3のデータを手軽に閲覧できる社内向けツールを作成することができました。

# ツールを作成した結果

このツールを作成したことで、以下のような改善ができました。

- レビューやデバッグにかかる時間が減少した
- データの中身が可視化されたことで、不正なデータや異常なデータが来ていないかを一目で確認することができるようになった
- 他チームで障害が発生しデータの更新が止まっていても気づけるようになった

デバッグにかかる時間が減少したことで、本来の開発業務にかける時間をより増やすことができました。

# まとめ

HonoとAWS Lambdaを使って業務改善ツールを作成しました。

Honoを使用したことで、短期間でツールを開発することができました。Honoはmiddleware、contextといったAPIのデザインに一貫性があり、学習コストが低く、導入しやすかったです。
またzod validatorなどを使用し、型安全を保ったコードを記述することができた点もよかったです（expressだとcontextがany型になりがち）。

こうしたツールをサクッと作りたい時はHonoが最適だと感じました！