AWS SAM CLIを用いてLambda+RubyでGemを使う方法

## 概要
LambdaでRubyを使う際にNokogiriなどのGemを使おうとするとエラになってしまうので動かせるようにする

## 環境設定
※こちらはある程度されているものだと仮定します

ここらへんの記事を参考にcliツールなどを入れてください
https://qiita.com/itaya/items/a0f22addaab04456cae4

## AWS側の準備
S3のバケットを用意
![スクリーンショット 2022-12-17 5.21.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/ca546b7f-7bf1-d7e7-75f3-21d4a15060da.png)


## 初期設定
プロジェクト名=好きな名前を指定してください
```sh
sam init --runtime ruby2.7 --name プロジェクト名
```
下記のように選択肢を迫られるので、1→1→nを選択します
```sh
Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
	1 - Hello World Example
	2 - Multi-step workflow
Template: 1

Based on your selections, the only Package type available is Zip.
We will proceed to selecting the Package type as Zip.

Based on your selections, the only dependency manager available is bundler.
We will proceed copying the template using bundler.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: n
```
そうするとディレクトリが一つ出来上がります。

## コーディング
ディレクトリの中のコードを変更していきます
hello_world/
このディレクトリの中がLambdaの本体コードになるのでこちらを変更します
app.rb
```rb
# require 'httparty'
require 'json'
require 'nokogiri'
require 'uri'
require 'kconv'
require 'net/http'

def lambda_handler(event:, context:)
  area = URI.encode_www_form_component('横浜')
  keyword = URI.encode_www_form_component('居酒屋')
  
  uri = URI.parse("https://r.gnavi.co.jp/area/jp/rs/?fwp=#{area}&date=&fw=#{keyword}")
  request = Net::HTTP::Get.new(uri)
  request["Authority"] = "r.gnavi.co.jp"
  request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
  request["Accept-Language"] = "ja"
  request["Cache-Control"] = "max-age=0"
  request["Cookie"] = "_td_global=2c7201bb-65d9-447f-8871-5c8aef70e6f0; _ra=1664900409701|e581f62a-e16f-4c02-97dc-b7ab203924e6; GU=e9f8c8528b624ea8cb1a55aadf705bd0; gt=GT139faa476002ac1e4ae520fpfeoIzpEqTDWQ1Rwc2xzV; ds=622474de466075942cc80e90a606c14bc6c474c7b09327535e48d587017aa4c0; gUser=03139faa476003ac1e4ae520L_I2dpFCb1q8eMMN-5-LmU; gcom=%7B%22login_type%22%3A1%2C%22guser_type%22%3A0%7D; _gid=GA1.3.151665219.1669743686; __gads=ID=61224817bcdcc5e2:T=1669743685:S=ALNI_MYQItLoO9f62eC3t0aHssBPge-pXQ; __gpi=UID=00000b86e8eecc21:T=1669743685:RT=1669743685:S=ALNI_MZ324J7fmISVdaU-A1IuoqdhZBTIQ; _ts_yjad=1669743686386; _fbp=fb.2.1669743686439.1159228644; _gcl_au=1.1.1560200380.1669743686; __pp_uid=INDH6tuKhtkFKURk66AXkbVTWOoJTybu; __lt__cid=c5331b8a-2798-4df1-9a8c-afb6b1af0c3c; __lt__sid=ab800c27-56441560; _dctagfq=1318:1670338799.0.0|1319:1670338799.0.0|1320:1670338799.0.0|1321:1670338799.0.0|1536:1670338799.0.0|1841:1670338799.0.0|1856:1670338799.0.0|1871:1670338799.0.0|1886:1670338799.0.0|1901:1670338799.0.0|1916:1670338799.0.0|1931:1670338799.0.0; ___o2u_o2id=0793b44a-526d-4f6f-bbfb-c923eb5be40f; rtosrch=gg7t002%3Dhttps%253A%252F%252Fr.gnavi.co.jp%252Farea%252Fjp%252Frs%252F%253Ffwp%253D%2525E6%2525A8%2525AA%2525E6%2525B5%25259C%2526date%253D%2526fw%253D%2525E3%252581%25259F%2525E3%252581%252593%2525E7%252584%2525BC%2525E3%252581%25258D%26a567203%3Dhttps%253A%252F%252Fr.gnavi.co.jp%252Farea%252Fjp%252Frs%252F%253Ffw%253D%2525E5%2525B1%252585%2525E9%252585%252592%2525E5%2525B1%25258B%2526fwp%253D%2525E6%2525A8%2525AA%2525E6%2525B5%25259C; GHistory=a567203%3A110%3A1669744542%2Cgg7t002%3A110%3A1669744522; ghistory_reserve=a567203%3A1669744542%2Cgg7t002%3A1669744522; __cribnotes_prm=__t_1669744547013_%7B%22uuid%22%3A%227a38921c-4d2e-4d30-bcb9-80d0686da7f0%22%7D; cto_bundle=sGp-Ll9kUDVaaHJYMHN3SkFtYyUyQkFmUTh2QWdka0pTQ0xqWlhHVFpETzB3ckh4dG1ya0J4NTB1Y0Z1V09mOUtMRDJWRlBKbDNSU2FTMWFDRXgyOFU4Q0l6UzAzYWFoWE9TMVd0WmVqOFZVcjBmQ3JHVHJyNkFodzhVcDlKTGdRYTBIWXNEdHdET3RzeENSc0Q0eDRGdUlwJTJGS3pWJTJGaXk1QW9sajk1ZUhJRHNaelpaYSUyRllHR0klMkZlNnhWWXIlMkJYTXB3eU00eUw; s_sess=%20sc_oncook%3D%3B%20sc_prop1%3Dr%3B%20cpnt_referer%3D%3B; _dc_gtm_UA-43329175-1=1; _td=639fb236-c732-4fb7-b246-0a6ed66c2a87; _ga_L9BHK8C28C=GS1.1.1669743685.1.1.1669744820.51.0.0; _ga=GA1.1.111137152.1669743686"
  request["Sec-Ch-Ua"] = "\"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\""
  request["Sec-Ch-Ua-Mobile"] = "?0"
  request["Sec-Ch-Ua-Platform"] = "\"macOS\""
  request["Sec-Fetch-Dest"] = "document"
  request["Sec-Fetch-Mode"] = "navigate"
  request["Sec-Fetch-Site"] = "same-origin"
  request["Sec-Fetch-User"] = "?1"
  request["Upgrade-Insecure-Requests"] = "1"
  request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
  
  req_options = {
    use_ssl: uri.scheme == "https",
  }
  
  response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
    http.request(request)
  end
  
  doc = Nokogiri::HTML.parse(response.body.toutf8, nil, 'utf-8')
  results = doc.css('.style_restaurantNameWrap__wvXSR').map do |target|
    target.text
  end
  {
    statusCode: 200,
    body: {
      message: "Hello World!",
      results: results
      # location: response.body
    }.to_json
  }
end
```
上記のコードが何をしているかは

https://qiita.com/itaya/items/0cd39400e274b926d5be

これとか参考にしてください。
簡単に言うとぐるなびのサイトから情報を取得してパースしてます。

## ローカルでコードの実行
下記のコマンドでビルドして
```sh
sam build --use-container
```
下記のコマンドで実行すると
```sh
sam local invoke HelloWorldFunction --event events/event.json
```
こんな感じでAPIのレスポンスが返ってきてることがわかります。
```
Invoking app.lambda_handler (ruby2.7)
Skip pulling image and use local one: public.ecr.aws/sam/emulation-ruby2.7:rapid-1.66.0-x86_64.

Mounting /Users/itayayuuichirou/Documents/src/lambda/foo_scraper/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: dd6e7259-a4a0-4e33-bcac-8ca32c52071f Version: $LATEST
END RequestId: dd6e7259-a4a0-4e33-bcac-8ca32c52071f
REPORT RequestId: dd6e7259-a4a0-4e33-bcac-8ca32c52071f	Init Duration: 1.07 ms	Duration: 2778.83 ms	Billed Duration: 2779 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
{"statusCode":200,"body":"{\"message\":\"Hello World!\",\"results\":[\"日吉 居酒屋 徳 0\",\"個室居酒屋 わら焼き直七（なおしち） 東戸塚店0\",\"居酒屋 まるは 0\",\"居酒屋さざん 中山駅前店0\",\"居酒屋さざん 日ノ出町駅前店0\",\"中華居酒屋 彩 関内0\",\"京個室 居酒屋 楓（かえで） 横浜駅前店0\",\"居酒屋 土間土間 横浜西口店0\",\"炭火居酒屋 もも 0\",\"居酒屋 土間土間 新横浜店0\",\"居酒屋 安ちゃん 0\",\"創作居酒屋 りき あざみ野店0\",\"〆蕎麦居酒屋 九 0\",\"中華居酒屋 ぼうず 0\",\"寿司居酒屋 七福 大口店0\",\"寿司居酒屋 太郎丸 上大岡店0\",\"寿司居酒屋 七福 戸塚店0\",\"和風居酒屋 末八 0\",\"寿司居酒屋 七福 上大岡店0\",\"九州居酒屋 エビス 市が尾店0\"]}"}%
```

## デプロイ
では、このコードをデプロイしていきます。
```sh
sam package --output-template-file output.yaml --s3-bucket バケット名
sam deploy --template-file output.yaml --stack-name バケット名 --capabilities CAPABILITY_IAM
```

表示されるURLを叩くと
![スクリーンショット 2022-12-17 5.56.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/b61b7ac7-a974-9221-2cc9-e07a2c471bad.png)
こんな感じでJSONが返ってくるかと思います。

以上！！
(細かい動きとかなんでそうなるのかは理解できていないので、勉強します...)