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」良かったです。ここ最近あまり界隈の話題にキャッチアップできなかったこともあったり、とても勉強になりました。

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

Amplify Cache の有効期限について理解する

Amplify Librariesには Cacheという機能があります。

Webアプリケーションでこの機能を使うとLocalStorageに任意の値をキャッシュしてくれるとのこと(オプションでSessionStorageにも保存可能です)。

Amplify Libraries経由でキャッシュ機能を使うメリットとしては有効期限を指定できるという点で、

  • アプリケーション全体で共通の有効期限を指定
  • アイテムごとに有効期限

の2パターンの設定が可能です。

続きを読む

OpenSearch をローカル環境で起動する、そしてRubyからクエリを実行する

表題のことをやってみました。 今年のre:InventでOpenSearch Serverlessが発表されたので、いい機会だしいっちょOpenSearch触ってみるかと思った次第。

最初はOpenSearch Serverlessを起動してみたりしたんですが、2〜3日過ぎたら請求が$120くらい増えててビビって消しました。

一時的な増加なのかもしれないが

ところがその数日後に請求額を見てみると、そのOpenSearchの利用料がきれいに消えていたのです。 何が起こったんでしょうね。

ともあれ、Serverlessだからといってタダで使えるわけではないので、とりあえずOpenSearchを雑に使ってみようということでローカル環境でOpenSearchを起動してみることにしたのでした。

続きを読む

VSCode Remote Containers で Railsの開発環境を作る

VS Code Remote Containers のウィザード?を使えば自分でDockerfile書かなくてもPostgresも一緒に状態で環境作ってくれる様子。

続きを読む

AWS Amplify のビルドで『The input value type 'AuthRule' is not present when resolving type 'AMPLIFY'』が発生した際の対応

AWSの発表しているAmplify + Reactで簡単なアプリケーションをデプロイするというチュートリアルをやっていたところ、表題の問題に遭遇。

https://aws.amazon.com/jp/getting-started/hands-on/build-react-app-amplify-graphql/module-four/

ローカルでの動作は問題なくGraphQLを使ったデータ登録ができたものの、その変更をpushし、amplifyにデプロイしようとしたところで以下のようなエラーが出てビルドに失敗した。

AWS_Amplify_Console.png

CloudFormation上では以下のようなログ CloudFormation_-_スタック_amplify-amplifyreact-master-144648-apiamplifyreact-5V93MRL0X15Y.png

続きを読む

Instant Potを使った簡単ほろほろチキンのスパイスカレー試作

※ "試作" とタイトルに入れた通り、出来上がりにはあまり満足していない。 鶏肉はホロホロになったものの、味がしっかりしみておらず、カレー全体としても塩っ気が足りない気がした。

  • 鶏肉を圧力鍋にかけて柔らかくしつつ鶏のスープを作り、それにスパイスカレーの素を加えればお手軽にほろほろチキンのカレーができあがるのでは?
  • 鶏肉に軽く焼き目をつけて圧力をかける
  • スパイスカレーの素を作る
  • 圧力をかけた鶏肉を入れる
  • できました

うちでは Instant Potがかなり活躍している。 鶏肉(またはウィンナー、ベーコン)・キャベツ・じゃがいも入れてコンソメキューブを入れて圧力をかければサクッと野菜スープ(ないしポトフ)ができあがる。 野菜がドロッドロになるけど僕はこれくらいが食べやすくてすき。このスープを週1~2で食べるようになったら体重が2~3キロ減った。

ところで本日 1/22はカレーの日らしい。

www.curry.or.jp

ということで

鶏肉を圧力鍋にかけて柔らかくしつつ鶏のスープを作り、それにスパイスカレーの素を加えればお手軽にほろほろチキンのカレーができあがるのでは?

と思いやってみた次第。

これまでに何度もスパイスカレーを作ってきたものの、実はあまり安定して満足のいくものが作れていない。できるだけ簡単に、かつ再現性の高いレシピを目指したい。

いろいろなレシピを試してみたけど、最近はこちらの作り方を参考にしている。

note.com

あとはこちらも。

www.hotpepper.jp

続きを読む

Ruby 2.5.0コンテナでRails6の開発環境を作るときのトラブルシューティング

こちらのハンズオンをやっていたところ、いくつかの問題に遭遇したので対処法をまとめておく。

Rails アプリケーションをコンテナで開発しよう ! 第 1 回 - まずは Rails アプリケーション作りから

Rails7のインストールに失敗する

記事では Ruby2.5 & Rails6 を使用しているが、現時点(2022/1)での最新版は 7.0.1。 エラーメッセージにもあるように7.0.1 ではRuby2.7以上が必要であるため gem install railsに失敗する。

root@810c33297af8:/work# gem install rails
Fetching: concurrent-ruby-1.1.9.gem (100%)
Successfully installed concurrent-ruby-1.1.9
Fetching: i18n-1.8.11.gem (100%)
Successfully installed i18n-1.8.11
Fetching: tzinfo-2.0.4.gem (100%)
Successfully installed tzinfo-2.0.4
Fetching: activesupport-7.0.1.gem (100%)
ERROR:  Error installing rails:
    There are no versions of activesupport (= 7.0.1) compatible with your Ruby & RubyGems. Maybe try installing an older version of the gem you're looking for?
    activesupport requires Ruby version >= 2.7.0. The current ruby version is 2.5.0.

gem install のオプションでRailsのバージョンを指定してインストールすることとした。

root@810c33297af8:/work# gem install -v 6.0.3.2 rails

Nokogiriのインストールに失敗する

さて、Railのバージョン指定をして改めてgem installを実施したところ、

root@810c33297af8:/work# gem install -v 6.0.3.2 rails
...
Fetching: activesupport-6.0.3.2.gem (100%)
Successfully installed activesupport-6.0.3.2
ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
    bad response Forbidden 403 (https://api.rubygems.org/quick/Marshal.4.8/nokogiri-1.13.0-x64-unknown.gemspec.rz)

Nokogiri 1.13.0のインストールに失敗している。 403なのでライブラリが不足している的なやつではないみたい。

rubygems.org でNokogiriの過去バージョンを調べて 1.12.5 を予めインストールすることで解決。

f:id:jacoyutorius:20220108065847p:plain

root@810c33297af8:/work# gem install nokogiri -v 1.12.5
Fetching: nokogiri-1.12.5-x86_64-linux.gem (100%)
Successfully installed nokogiri-1.12.5-x86_64-linux
1 gem installed
root@810c33297af8:/work# gem install -v 6.0.3.2 rails
Fetching: loofah-2.13.0.gem (100%)
Successfully installed loofah-2.13.0
Fetching: rails-html-sanitizer-1.4.2.gem (100%)
Successfully installed rails-html-sanitizer-1.4.2
Fetching: rails-dom-testing-2.0.3.gem (100%)
Successfully installed rails-dom-testing-2.0.3
Fetching: builder-3.2.4.gem (100%)
Successfully installed builder-3.2.4
Fetching: erubi-1.10.0.gem (100%)
Successfully installed erubi-1.10.0
Fetching: actionview-6.0.3.2.gem (100%)
Successfully installed actionview-6.0.3.2
Fetching: actionpack-6.0.3.2.gem (100%)
Successfully installed actionpack-6.0.3.2
Fetching: activemodel-6.0.3.2.gem (100%)
Successfully installed activemodel-6.0.3.2
Fetching: activerecord-6.0.3.2.gem (100%)
Successfully installed activerecord-6.0.3.2
Fetching: globalid-1.0.0.gem (100%)
Successfully installed globalid-1.0.0
Fetching: activejob-6.0.3.2.gem (100%)
Successfully installed activejob-6.0.3.2
Fetching: mini_mime-1.1.2.gem (100%)
Successfully installed mini_mime-1.1.2
Fetching: mail-2.7.1.gem (100%)
Successfully installed mail-2.7.1
Fetching: actionmailer-6.0.3.2.gem (100%)
Successfully installed actionmailer-6.0.3.2
Fetching: nio4r-2.5.8.gem (100%)
Building native extensions. This could take a while...
Successfully installed nio4r-2.5.8
Fetching: websocket-extensions-0.1.5.gem (100%)
Successfully installed websocket-extensions-0.1.5
Fetching: websocket-driver-0.7.5.gem (100%)
Building native extensions. This could take a while...
Successfully installed websocket-driver-0.7.5
Fetching: actioncable-6.0.3.2.gem (100%)
Successfully installed actioncable-6.0.3.2
Fetching: mimemagic-0.3.10.gem (100%)
Building native extensions. This could take a while...
Successfully installed mimemagic-0.3.10
Fetching: marcel-0.3.3.gem (100%)
Successfully installed marcel-0.3.3
Fetching: activestorage-6.0.3.2.gem (100%)
Successfully installed activestorage-6.0.3.2
Fetching: actionmailbox-6.0.3.2.gem (100%)
Successfully installed actionmailbox-6.0.3.2
Fetching: actiontext-6.0.3.2.gem (100%)
Successfully installed actiontext-6.0.3.2
Fetching: thor-1.2.1.gem (100%)
Successfully installed thor-1.2.1
Fetching: method_source-1.0.0.gem (100%)
Successfully installed method_source-1.0.0
Fetching: railties-6.0.3.2.gem (100%)
Successfully installed railties-6.0.3.2
Fetching: sprockets-4.0.2.gem (100%)
Successfully installed sprockets-4.0.2
Fetching: sprockets-rails-3.4.2.gem (100%)
Successfully installed sprockets-rails-3.4.2
Fetching: rails-6.0.3.2.gem (100%)
Successfully installed rails-6.0.3.2
29 gems installed