Hono JavaScript AWS Lambda デプロイ

今回は、JavaScirptのサーバーサイドフレームワークであるHonoで簡単なAPIを実装し、
AWS Lambdaにデプロイしてみた際のメモです。

手間ですが全て手動で行っています。当然、terraformやCloud Formationで自動化できると思います。

バージョン

Node.js:v24.11.1
Hono:4.0.0


honoインストール

package.json初期化

npm init -y
honoインストール(node_module整備)
npm install hono @hono/node-server

対話形式でHonoテンプレートプロジェクトごとインストールしたい場合は、以下などで行います。

npm create hono@latest

簡易アプリ実装

POST、GET等の簡単なサンプル実装です。

以下はローカル実行用です。後述でほぼ同様の内容のLambda実行用ファイルも作成します。

src/index.js


import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'

// Honoアプリケーションインスタンスの作成
const app = new Hono()

// ミドルウェア設定
app.use('*', logger())
app.use('*', cors())

// ルート
app.get('/', (c) => {
  return c.json({ 
    message: 'Honoへようこそ!',
    timestamp: new Date().toISOString()
  })
})

// パラメータ付きGETリクエスト
app.get('/money/:type_str', (c) => {
  const type_str = c.req.param('type_str')
  
  // 通貨記号マップ
  const symbols = {
    '円': '¥',
    'ドル': '$'
  }
  
  const symbol = symbols[type_str] || '?'
  
  return c.json({ 
    currency: type_str,
    symbol: symbol,
    message: `${type_str}の記号は${symbol}です。`
  })
})

// POSTリクエストの例
app.post('/money/calc', async (c) => {
  const body = await c.req.json()
  const { amount, currency } = body

  // 為替レート(本来は外部APIから取得)
  const exchangeRates = {
    '円': 1,
    'ドル': 110
  }

  const rate = exchangeRates[currency] || 1
  const convertedAmount = amount * rate

  return c.json({
    message: '変換が完了しました',
    originalAmount: amount,
    currency: currency,
    convertedAmount: convertedAmount
  }, 201)
})

// HTMLレスポンスの例(簡素デザイン/一重エスケープ+テンプレ不使用)
app.get('/html/response_sample', (c) => {
  const html =
    '<!DOCTYPE html>' +
    '<html lang="ja">' +
      '<head>' +
        '<meta charset="utf-8" />' +
        '<title>Hono App</title>' +
        '<style>' +
          'body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 24px; line-height: 1.6; }' +
          'h1 { font-size: 20px; margin-bottom: 12px; color: #111827; }' +
          'ul { padding-left: 20px; }' +
          'li { margin: 4px 0; }' +
          'code { background: #f3f4f6; padding: 2px 4px; border-radius: 3px; }' +
        '</style>' +
      '</head>' +
      '<body>' +
        '<h1>Hono サンプルエンドポイント</h1>' +
        '<ul>' +
          '<li><code>GET /</code> — トップページ(JSON)</li>' +
          '<li><code>GET /money/:type_str</code> — 通貨記号(例: 円、ドル)<br><small>例:</small><code>http://localhost:3000/money/円</code></li>' +
          '<li><code>POST /money/calc</code> — 通貨変換<br><small>例:</small><code>curl -X POST http://localhost:3000/money/calc -H "Content-Type: application/json" \'-d {"amount": 10, "currency": "ドル"}\'</code></li>' +
        '</ul>' +
      '</body>' +
    '</html>';

  return c.html(html);
});

// 404ハンドラー
app.notFound((c) => {
  return c.json({ 
    message: 'ページが見つかりません' 
  }, 404)
})

// エラーハンドラー
app.onError((err, c) => {
  console.error(`エラー: ${err}`)
  return c.json({ 
    error: 'サーバーエラーが発生しました',
    message: err.message 
  }, 500)
})

// サーバー起動
const port = 3000
console.log(`🚀 サーバーが起動しました: http://localhost:${port}`)

serve({
  fetch: app.fetch,
  port
})


ローカル挙動確認

開発サーバー起動
npm run dev

Hono sample project

http://localhost:3000

Hono sample project npm run dev

http://localhost:3000/money/ドル

Hono sample project npm run dev

curl -X POST http://localhost:3000/money/calc -H "Content-Type: application/json" -d '{"amount": 10, "currency": "ドル"}'
Hono sample project npm run dev
http://localhost:3000/html/response_sample

Hono sample project npm run dev


Lambda デプロイ 資材作成

Lambda実行ファイル作成

既存のindex.jsをベースにLambda実行ファイルを作成します。
ほぼ同じ内容ですが、以下の部分を修正して作成します。

  • インポート
    削除:import { serve } from ‘@hono/node-server’
    追加:
    import { handle } from ‘hono/aws-lambda’
  • サーバー起動
    削除:serve({ fetch: app.fetch, port: 3000 })
    追加:export const handler = handle(app)

lambda_function.js


import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'

const app = new Hono()

// ミドルウェア設定
app.use('*', logger())
app.use('*', cors())

// ルート
app.get('/', (c) => {
  return c.json({ 
    message: 'Honoへようこそ!',
    timestamp: new Date().toISOString()
  })
})

// パラメータ付きGETリクエスト
app.get('/money/:type_str', (c) => {
  const type_str = c.req.param('type_str')
  
  // 通貨記号マップ
  const symbols = {
    '円': '¥',
    'ドル': '$'
  }
  
  const symbol = symbols[type_str] || '?'
  
  return c.json({ 
    currency: type_str,
    symbol: symbol,
    message: `${type_str}の記号は${symbol}です。`
  })
})

// POSTリクエストの例
app.post('/money/calc', async (c) => {
  const body = await c.req.json()
  const { amount, currency } = body

  // 為替レート(本来は外部APIから取得)
  const exchangeRates = {
    '円': 1,
    'ドル': 110
  }

  const rate = exchangeRates[currency] || 1
  const convertedAmount = amount * rate

  return c.json({
    message: '変換が完了しました',
    originalAmount: amount,
    currency: currency,
    convertedAmount: convertedAmount
  }, 201)
})

// クエリパラメータの例
app.get('/money/multiplication', (c) => {
  const money_type = c.req.query('money_type')
  const count = c.req.query('count')

  // 単価マップ
  const unitPrices = {
    '円': 100,
    'ドル': 1
  }

  // 計算処理
  const unitPrice = unitPrices[money_type] || 0
  const countNum = parseInt(count, 10) || 0
  const result = unitPrice * countNum

  return c.json({
    money_type: money_type,
    count: countNum,
    unitPrice: unitPrice,
    total: result
  })
})

// HTMLレスポンスの例(簡素デザイン/一重エスケープ+テンプレ不使用)
app.get('/html/response_sample', (c) => {
  const html =
    '<!DOCTYPE html>' +
    '<html lang="ja">' +
      '<head>' +
        '<meta charset="utf-8" />' +
        '<title>Hono App</title>' +
        '<style>' +
          'body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 24px; line-height: 1.6; }' +
          'h1 { font-size: 20px; margin-bottom: 12px; color: #111827; }' +
          'ul { padding-left: 20px; }' +
          'li { margin: 4px 0; }' +
          'code { background: #f3f4f6; padding: 2px 4px; border-radius: 3px; }' +
        '</style>' +
      '</head>' +
      '<body>' +
        '<h1>Hono サンプルエンドポイント</h1>' +
        '<ul>' +
          '<li><code>GET /</code> — トップページ(JSON)</li>' +
          '<li><code>GET /money/:type_str</code> — 通貨記号(例: 円、ドル)<br><small>例:</small><code>http://localhost:3000/money/円</code></li>' +
          '<li><code>POST /money/calc</code> — 通貨変換<br><small>例:</small><code>curl -X POST http://localhost:3000/money/calc -H "Content-Type: application/json" \'-d {"amount": 10, "currency": "ドル"}\'</code></li>' +
        '</ul>' +
      '</body>' +
    '</html>';

  return c.html(html);
});

// 404ハンドラー
app.notFound((c) => {
  return c.json({ 
    message: 'ページが見つかりません' 
  }, 404)
})

// エラーハンドラー
app.onError((err, c) => {
  console.error(`エラー: ${err}`)
  return c.json({ 
    error: 'サーバーエラーが発生しました',
    message: err.message 
  }, 500)
})

// Lambda用のハンドラーをエクスポート
export const handler = handle(app)

デプロイ用Zip作成

コマンド実行

zip -r lambda-deployment.zip src/lambda_function.js node_modules package.json

手動でも作成できますが、
src/lambda_function.jsnode_modules配下全て、package.jsonを含める形で作成します。

Hono sample project create zip
※本来Lambda実行用には、@hono/node-servernなどは不要です。
本番実行用の資材を作成する場合は、含める依存関係を整理することをオススメします。


AWS Lambda 作成・デプロイ

動作させるLambdaを作成してデプロイします。

AWS Lambda作成

関数名を任意の名称で命名し、ランタイム:Node.jsを指定します。

Hono Sample AWS Lambda Deploy

資材デプロイ

作成したZipファイルをアップロードしてデプロイします。
アップロード元のところよりアップロードできます。
Hono Sample AWS Lambda Deploy

Hono Sample AWS Lambda Deploy

Hono Sample AWS Lambda Deploy

アップロードされると、コードソース部分に内容が展開されます。
Hono Sample AWS Lambda Deploy

 


Lambda 設定調整

動作させるためのLambda設定を行なっていきます。

タイムアウト設定調整

念の為、タイムアウト時間を調整します。

Hono AWS Lambda Create EndPoint

エンドポイント作成

挙動確認用の関数URLを作成します。

Hono AWS Lambda Create EndPoint

認証タイプ:NONEを指定します。
※外部公開され全てのユーザーが実行できますのでご注意ください。

Hono AWS Lambda Create EndPoint

ここで作成された関数URLが挙動確認用になります。

Hono AWS Lambda Create EndPoint

ランタイム設定

ランタイム設定より作成したlambda_function.jsを実行するための設定を行います。

Hono AWS Lambda Runtime handler

ハンドラを以下のような形で指定します。

src/lambda_function.handler

Hono AWS Lambda Runtime handler


AWS Lambda Hono 挙動確認

設定が全て済んだら、関数URLで挙動確認を行います。

Hono AWS Lambda test

Hono AWS Lambda test

エラー等問題が起きた場合、
CloudWatchログでログを確認できますので確認してトラブルシュートします。
Hono AWS Lambda test


今回のメモは以上となります。

Honoは軽量で実装しやすいJavaScriptバックエンドフレームワークです。
特にLambdaとの相性が良いと感じます。

ルーティングも簡単に実装側で制御できますし、ちょっとしたAPIを用意するのに打って付けだと思います。

都内でエンジニアをやっています。 2017年に脱サラ(法人設立)しました。 仕事で調べたことや、気になったことをメモしています。
投稿を作成しました 186

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連投稿

検索語を上に入力し、 Enter キーを押して検索します。キャンセルするには ESC を押してください。

トップに戻る