Hono を触ってみた

# 概要
JavaScript ランタイムで動かせる、フロントエンドのないシンプルな Web アプリケーション フレームワーク。
Web API 構築ができるため、個人的に javascript 版 FastAPI だと思っている。

https://hono.dev/

https://qiita.com/StarduSt_cruSaderS/items/afd509a6666fc9c0495c

## 特徴
1. 超高速
1. 軽量
1. [5つの Router](https://hono.dev/docs/concepts/routers) から最適なルーティングを選択できる
1. [Web 標準の採用](https://hono.dev/docs/concepts/web-standard)により、様々なプラットフォーム (Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, Node.js) での動作が可能
1. 多くの[ミドルウェア](https://hono.dev/docs/concepts/middleware)やヘルパーが用意されている
1. typescript がデフォルト

https://devlog.mescius.jp/hono-quickstart/

# チュートリアル

https://github.com/alice0421/hono-web-api

## Bun チュートリアル
とりあえず Bun でチュートリアル。  
※ Volta だと Bun が管理できなかったので、Proto をバージョン管理ツールとして使用。

https://hono.dev/docs/getting-started/basic

## AWS Lambda チュートリアル
### Lambdalith の構成
各エンドポイントごとに Lambda を持つのではなく、1つの Lambda 関数で全エンドポイントを処理する構成。Hono はこの構成を作るのに便利な Web フレームワークの1つ。

今回は API Gateway 導入するほどでもないので、Lmabda Function URL を使用する。また、IaC は cdk とする。

https://zenn.dev/watany/articles/183d40f8e31a45

https://serverless.co.jp/blog/j94zz_4-m/

https://dev.classmethod.jp/articles/aws-lambda-function-urls-built-in-https-endpoints/

https://qiita.com/luton-mr/items/afe70781807bf3b5016a

### 実践

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

※ cdktf の CloudFormation テンプレート保存のための S3 課金 + Lambda 実行時の課金があることに注意（最後に完全削除する）。

※ docker (cdk で Lambda 関数をコンテナイメージとしてデプロイしようとする), npm (cdk 実行に必要) を予め準備しておくこと。

※ aws-cdk は内部で node を使用しているため、 bun のみでは動かせない。bun はあくまで typescript の実行環境として使用する。

#### 1. [Hono 公式の AWS Lambda での Setup](https://hono.dev/docs/getting-started/aws-lambda) に沿って、cdk の環境構築をする。
```shell
$ mkdir lambda-function-api

$ cd lambda-function-api

$ npx cdk init app -l typescript

$ bun add hono

$ mkdir lambda

$ touch lambda/index.ts
```

#### 2. `lambda/index.ts` を記述する。
```typescript
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'

const app = new Hono()

app.get('/', (c) => c.text('Hello Hono!'))

export const handler = handle(app)
```

#### 3. `lib/lambda-function-stack.ts` を記述する。
※ 今回は Lambda Function URL を使用するため、API Gateway の cdk は不要。

> [NodejsFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html) (デプロイ時に docker が必要)

```typescript
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as lambda from 'aws-cdk-lib/aws-lambda'
// Node.js ランタイムの Lambda を構築。フォルダ指定が必要な lambda.Function とは違い、単一ファイルの指定が可能。
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'

export class MyAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    // Lambda 関数を作成
    const fn = new NodejsFunction(this, 'lambda', {
      entry: 'lambda/index.ts',
      handler: 'handler',
      runtime: lambda.Runtime.NODEJS_20_X,
    })
    // 関数 URL を IAM 認証で設定
    fn.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    })
  }
}
```

#### 4. デプロイする。
※ bootstrap で作成されるものは、 cdk 実行に必要な IAM や CloudFormation テンプレート保存に必要な S3 など。「CloudFormation > CDKToolkit」に実際に作成されるものが記載されている。

https://www.cloudbuilders.jp/articles/3511/

```shell
# cdk が初めての場合は下記コマンドの実行が必要
# $ npm run cdk bootstrap

# 差分確認
$ npm run cdk diff
# Resources
# [+] AWS::IAM::Role lambda/ServiceRole lambdaServiceRole*****
# [+] AWS::Lambda::Function lambda lambda*****
# [+] AWS::Lambda::Url lambda/FunctionUrl lambdaFunctionUrl*****

# デプロイ
$ npm run cdk deploy
```

#### 5. Postman で 関数 URL を叩いてみる
IAM 認証しているため、「Authorization > AWS Signature」で下記を設定してから叩く。
- AccessKey
- SecretKey
- AWS Region：Lambda 関数 URL があるリージョン
- Service Name：lambda

下記が Response として返ってきたら成功。
```json
Hello Hono!
```

#### 6. （おまけ）課金がもったいないので、cdk ごと削除する
今回作ったリソースを cdk で削除する。
```shell
$ npm run cdk destroy
```

下記手順で cdk 自体を削除する。
1. 「CloudFormation > スタック > CDKToolkit」を削除。
    - スタックに紐づくリソースが削除される。
1. 上記スタックに紐ついている S3 は消えないので、手動で削除。

※ cdk 再構築時は、`cdk bootstrap` コマンドを叩けば良い。