Hono + AWS Lambda を試す(「Media-JAWS × JAWS-UG 静岡支部 × 浜松支部 コラボ勉強会 202605」に参加してきた)

「Media-JAWS × JAWS-UG 静岡支部 × 浜松支部 コラボ勉強会 202605」に参加してきまして。

jawsug-shizuoka.connpass.com

ここでちょっとだけ話題がでたHono、気にはなっていたんだけどCloudflare用のOSSだとばかり思っていて Lambdaにも使えるとはしらなかった。

iret.media

ということで試してみました。


初めてなのでチュートリアルどおりにやる。

AWS Lambda - Hono

mkdir my-app
cd my-app
cdk init app -l typescript
pnpm add hono
pnpm add -D esbuild
mkdir lambda
touch lambda/index.ts

"Hello World"を出力するlambdaファンクション。

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

const app = new Hono()

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

export const handler = handle(app)

Function URL とつなげる。

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

    const fn = new NodejsFunction(this, 'lambda', {
      entry: 'lambda/index.ts',
      handler: 'handler',
      runtime: lambda.Runtime.NODEJS_22_X,
    })
    const fnUrl = fn.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    })
    new cdk.CfnOutput(this, 'FunctionUrl', {
      value: fnUrl.url,
    })
  }
}

ローカルで実行するにはざっくり以下の2つの方法があるらしい。

  1. ローカルで起動するNodejsサーバー用のindex.tsを用意する
  2. sam localを使う

今回は使い慣れているSAM CLIを使う方法で試してみました。 cdk synth でCDKのコードを

➜  my-app git:(main) ✗ cdk synth
Bundling asset MyAppStack/lambda/Code/Stage...

  ...mp-a89236c5ef003b96aa279a8c504023819e10b049161751c63cb7078594a48619-building/index.js  70.6kb

⚡ Done in 12ms
Resources:
  lambdaServiceRole494E4CA6:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Metadata:
      aws:cdk:path: MyAppStack/lambda/ServiceRole/Resource
  lambda8B5974B5:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::Sub: cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}
        S3Key: 75d39caa492c4878600b101ce02508c3f8080484577e926c2d93571c0f28e355.zip
      Handler: index.handler
      Role:
        Fn::GetAtt:
          - lambdaServiceRole494E4CA6
          - Arn
      Runtime: nodejs22.x
    DependsOn:
      - lambdaServiceRole494E4CA6
    Metadata:
      aws:cdk:path: MyAppStack/lambda/Resource
      aws:asset:path: asset.75d39caa492c4878600b101ce02508c3f8080484577e926c2d93571c0f28e355
      aws:asset:is-bundled: true
      aws:asset:property: Code
  lambdaLogGroup264FD7A1:

~

あれ Your session has expired or credentials have changed. Please reauthenticate using 'aws login' が出た。 AWSにログインする必要があるんだっけ?

➜  my-app git:(main) sam local invoke lambda -t ./cdk.out/MyAppStack.template.json
No current session found, using default AWS::AccountId
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/ServiceRole/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/LogGroup/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/FunctionUrl/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/ServiceRole/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/LogGroup/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/FunctionUrl/Resource', using
default logical id
Invoking index.handler (nodejs22.x)

Error: Your session has expired or credentials have changed. Please reauthenticate using 'aws login'.

ということで aws login

➜  my-app git:(main) aws login
Attempting to open your default browser.
If the browser does not open, open the following URL:

~

リトライ。

➜  my-app git:(main) sam local invoke lambda -t ./cdk.out/MyAppStack.template.json
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/ServiceRole/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/LogGroup/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/FunctionUrl/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/ServiceRole/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/LogGroup/Resource', using
default logical id
Cannot detect function id from aws:cdk:path metadata 'MyAppStack/lambda/FunctionUrl/Resource', using
default logical id
Invoking index.handler (nodejs22.x)
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-nodejs22.x
Building image....................................................................................................
Using local image: public.ecr.aws/lambda/nodejs:22-rapid-x86_64.

Mounting
/Users/ogiyuto/work/hono/my-app/cdk.out/asset.75d39caa492c4878600b101ce02508c3f8080484577e926c2d9357
1c0f28e355 as /var/task:ro,delegated, inside runtime container
SAM_CONTAINER_ID: 3d07f49d2ffc994322ec0042b969ea82abfc67cf50133e6e338041c95e912782
START RequestId: a125673e-0e91-4e04-8713-2d14d0c87d36 Version: $LATEST
END RequestId: a125673e-0e91-4e04-8713-2d14d0c87d36
REPORT RequestId: a125673e-0e91-4e04-8713-2d14d0c87d36  Init Duration: 0.27 ms  Duration: 782.29 msBilled Duration: 783 ms  Memory Size: 128 MB     Max Memory Used: 128 MB
{"body": "Hello, World!", "statusCode": 200, "isBase64Encoded": false, "headers": {"content-type": "text/plain;charset=UTF-8"}}

うん。ちゃんと返ってきたね。

まぁこれだけだとHono使っている意味があんまりなくて、複数のルーティングがあるバックエンドを構築するときに威力を発揮するっぽい。

Honoはエコシステムも豊富らしくOAuth認証やエラーハンドリングの機能もあるみたい。以前の仕事でlambdaをいくつか作ったときにエラーハンドリングがめんどくさかったのを思い出した。


ところで、「Media-JAWS × JAWS-UG 静岡支部 × 浜松支部 コラボ勉強会 202605」良かったです。ここ最近あまり界隈の話題にキャッチアップできなかったこともあったり、とても勉強になりました。

あと、別業種のみなさんでも余裕でいい感じのアプリケーションを作っているのを見せつけられたのでこりゃ頑張らんといかんなぁと思った次第。