LaravelからDynamoDBのデータ取得|Lambda×API Gateway経由

標題にある通り、LaravelからDynamoDBのデータを取得します。
その際に、AWSサービスの「Lambda」と「API Gateway」経由して取得します。

今回、かなり参考にさせて頂いた記事がこちらです。
AWS API GatewayとLambdaでDynamoDB操作

API Gateway → Lambda → DynamoDB までの部分はこちらを参考にさせて頂きつつ、
・途中でエラーで詰まった部分の紹介
・API GatewayとLaravelとの連携部分についての紹介(curlを利用します。)
をしていきます。

■前提

・Laravelインストール済み
・AWSアカウント取得済み

LaravelからDynamoDBのデータ取得の流れ

①:DynamoDBのテーブル、レコード作成
②:Lambda作成
③:API Gateway作成
④:API Gatewayテスト実施
⑤:API Gateway公開
⑥:ローカル環境(mac / ターミナル)から、API Gatewayへリクエスト
⑦:LaravelからAPI Gatewayへリクエスト
おまけ:LaravelからAPI Gatewayの通信に認証を追加

①〜⑤は、こちらの記事を参考に進めて頂けたらと想います。 AWS API GatewayとLambdaでDynamoDB操作 

⑥:ローカル環境(mac / ターミナル)から、API Gatewayへリクエスト

①~⑤で、API Gatewayテストが完了し、DynamoDBのデータが正しくResponseされているでしょうか。

■SCANを実施したい場合のコマンド

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d '{"OperationType":"SCAN"}' | jq

ここで自分が見誤った部分が、リクエストする際のURL部分です。
ステージエディターのURLを利用すれば問題ないのですが、階層によってURLが違うので注意して下さい。
こちらの方と同じ勘違いをして、「Missing Authentication Token」となってしまいました。 【AWS】APIGatewayのURLにアクセスするとエラー「Missing Authentication Token」が表示される

⑦:LaravelからAPI Gatewayへリクエスト

ローカル環境から、curlを利用してデータが返ってきましたか。

curlを利用して、LaravelからAPI Gatewayへリクエストして、DynamoDBのデータを取得していきます。

public function index()
{
    
    $header = [
        'Content-Type: application/json',
    ];

        $params = [
        "OperationType" => "SCAN"
    ];

        
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, env('AWS_APIGATEWAY_URL'));
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    
    $output= curl_exec($curl);
    $result = json_decode($output);
    curl_close($curl);

    dd($result);
    }

curlはPHPに標準で含まれているので、importをする必要はありません。

env(‘AWS_APIGATEWAY_URL’)

ステージの呼び出しURLを指定して下さい。

curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($params));

連想配列から、jsonへ変換しています。

これで、dd($result);で、ターミナルからcurlしたデータと同じデータが返ってくると思います。

LaravelからAPI Gatewayの通信に認証を追加

下記にてまとめております。

Lambdaでselenium実行 / 空のHTMLがreturn|

Lambda(AWS) ✕ seleniumを利用して、下記の関数コードでスクレイピングを実行した。(Lambdaの設定詳細は割愛)

from selenium import webdriver
 import os
 os.environ['HOME'] = '/opt/'
 def lambda_handler(event, context):
     options = webdriver.ChromeOptions()
     options.add_argument("--headless")
     options.add_argument("--disable-gpu")
     options.add_argument("--hide-scrollbars")
     options.add_argument("--single-process")
     options.add_argument("--ignore-certificate-errors")
     options.add_argument("--window-size=880x996")
     options.add_argument("--no-sandbox")
     options.add_argument("--homedir=/tmp")
     options.binary_location = "/opt/headless/python/bin/headless-chromium"
     #headless-chromiumへのPATHは、ご自身の環境に応じて設定して下さい。

    browser = webdriver.Chrome("/opt/headless/python/bin/chromedriver", options=options)
    #choromedriverへのPATHは、ご自身の環境に応じて設定して下さい。

    browser.get("https://www.google.com/")
    title = browser.title
   
    print(title)
    print(browser.page_source)    
   
    browser.close()
    return 'ok'

すると、printしたかったtitleが空白。
page_sourceが下記のように空っぽのHTMLで返ってきた。

<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>

解決方法

optionに下記を追加して下さい。

options.add_argument('--disable-dev-shm-usage')

どうやら、Chromeがメモリ不足でクラッシュしてしまっているようです。(Lambdaの設定でメモリは十分に高くしていても関係ないようです。)

メモリ保持場所を/dev/shmの代わりに/tmpディレクトリを使うことができる設定です。

参考;

https://qiita.com/yoshi10321/items/8b7e6ed2c2c15c3344c6

追加したコード

from selenium import webdriver
 import os
 os.environ['HOME'] = '/opt/'
 def lambda_handler(event, context):
     options = webdriver.ChromeOptions()
     options.add_argument("--headless")
     options.add_argument("--disable-gpu")
     options.add_argument("--hide-scrollbars")
     options.add_argument("--single-process")
     options.add_argument("--ignore-certificate-errors")
     options.add_argument("--window-size=880x996")
     options.add_argument("--no-sandbox")
     options.add_argument("--homedir=/tmp")
     options.add_argument('--disable-dev-shm-usage')
     options.binary_location = "/opt/headless/python/bin/headless-chromium"
     #headless-chromiumへのPATHは、ご自身の環境に応じて設定して下さい。

    browser = webdriver.Chrome("/opt/headless/python/bin/chromedriver", options=options)
    #choromedriverへのPATHは、ご自身の環境に応じて設定して下さい。

    browser.get("https://www.google.com/")
    title = browser.title
   
    print(title)
    print(browser.page_source)    
   
    browser.close()
    return 'ok'

【最小労力】AWS Lambdaの関数で、S3へファイルアップロードする方法

Lambda → S3 へファイルアップロードをする方法をコンパクトにお伝えします。 連携できるを確認したい、通信方法を理解したい、といった場合には最小労力での動かし方を把握しましょう。

S3、Lambdaそれぞれのサービスを設定していきましょう。

①:S3で、ファイルアップロード先のbucketを作成

S3のbucket作成しましょう。
バケット名、AWSリージョンを設定して → bucket作成

S3のbucket設定

②-1:Lambdaの関数を作成

関数の作成 >> 1から作成 を選択します。

実行ロールの部分が重要です。この後、S3にアップロードする際にS3へのアクセス権限が必要です。

赤枠で囲んだ部分が、ロールです。
後ほど、このロールにS3へのファイルアップロード可能なアクセス権限を付与していきます。

②-2:Lambdaの関数を作成:ファイルアップロードを実行するコードソース

関数のコードソースに書きを反映します。
下記部分は環境に応じて変更して下さい。
bucket = '{S3で作成したアップロード先のbucket名}'

import json import urllib.parse import boto3 import datetime def lambda_handler(event, context): try: # Get the object from the event and show its content type s3 = boto3.resource(‘s3’) bucket = ‘{S3で作成したアップロード先のbucket名}’ key = ‘test_{}.txt’.format(datetime.datetime.now().strftime(‘%Y-%m-%d-%H-%M-%S’)) file_contents = ‘S3へファイルアップロード’ obj = s3.Object(bucket,key) obj.put( Body=file_contents ) except Exception as e: print(e) raise e

②-3:Lambdaのテストイベント設定

イベント JSON部分に下記で指定した、形式を反映して下さい。

JSON イベント形式

{ “Records”: [ { “eventVersion”: “2.0”, “eventSource”: “aws:s3”, “awsRegion”: “us-east-1”, “eventTime”: “1970-01-01T00:00:00.000Z”, “eventName”: “ObjectCreated:Put”, “userIdentity”: { “principalId”: “EXAMPLE” }, “requestParameters”: { “sourceIPAddress”: “127.0.0.1” }, “responseElements”: { “x-amz-request-id”: “EXAMPLE123456789”, “x-amz-id-2”: “EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH” }, “s3”: { “s3SchemaVersion”: “1.0”, “configurationId”: “testConfigRule”, “bucket”: { “name”: “example-bucket”, “ownerIdentity”: { “principalId”: “EXAMPLE” }, “arn”: “arn:aws:s3:::example-bucket” }, “object”: { “key”: “test%2Fkey”, “size”: 1024, “eTag”: “0123456789abcdef0123456789abcdef”, “sequencer”: “0A1B2C3D4E5F678901” } } } ] }

③:Lambdaの実行ロールにS3へのアクセス権限を付与

Lambdaの設定 >> 実行ロール へ。

先程作成した「実行ロール」が記載されています。ここからリンク遷移をして下さい。

IAM Mangerへ飛びます。

Lambdaの実行ロールとなっているロール(リンク遷移でこればそのままでOK)に対して、
アクセス許可を追加 >> ポリシーをアタッチ
から
AmazonS3FullAccess をアタッチして下さい。

④:テストで確認

Deploy → テスト を実行。
S3の指定したbucketへファイルがアップロードされています。

以上です。

今回紹介した、S3へのファイルアップロード方法だけでは、あまり使いみちがありませんが、トリガーなども組み合わせると、サーバーレスで、S3にファイル格納をすることが可能です。