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の通信に認証を追加

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

Laravel,balde「@auth・Auth::user()」が反応しない件

今回、非常にピンポイントなシチュエーションによる問題です。

■前提条件

・マルチログイン認証機能で、guard: users,adminを2つ作成
・guardのdefaultをusers指定

■問題発生状況

・adminでログイン状態
・baldeにて、「@auth」や「Auth::user()」がnullで返ってくる

■原因

原因は、guardのdefault指定のようです。

config > auth.php

の中で、defaultを指定を下記でしておりました。

    'defaults' => [
        'guard' => 'users',
        'passwords' => 'users',
    ],

「@auth」や「Auth::user()」「Auth::login()」 等で呼び出すのは auth.php でdefault に指定したguardのようです。

adminでログイン状態でも、defaultがusersだったのでnullが返ってきたようです。

■解決策

defalut以外のguard を呼び出すには Auth::guard(‘admin’) のように guard 名を指定する必要があります。

Laravel認証後,認証ユーザーである情報をどこで保持するのか.

Laravelの認証後に、認証ユーザーであることをどこで判別しているのか。
疑問を調べてみました。

認証の設定方法によって違いますが、
laravelのdefaultでは、Sessionに設定されているかと思います。

app > config > auth.php

下記のようにdriverがsessionで指定されていると思います。

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],   
    ],

sessionではどのような情報として保持されているのか?

実際にどのような情報として保持しているのかを確認してみます。

・確認用のControllerの作成

<?php
 namespace App\Http\Controllers;
 use Illuminate\Http\Request;
 class TestSessionController extends Controller
 {
     //
     public function index(Request $request)
     {
     $data = $request->session()->all();     dd($data);  }
 }

・確認用のRouteの作成

Route::get('test', [TestSessionController::class, 'index'])->name('index');

ログイン完了後.  /testへ遷移してみる。

dd()によって、下記の情報が確認できると思います。

下記の部分がAuthのguardのsession部分です。
{guard} 部分は、guardで設定し、ログインに利用したguardの文字列が含まれます。

array:4 [▼
   "login_{guard}_XXXXXXXXXXXXXXXXXXXXXXXXX" => 1
 ]

例えば、マルチログイン対応で、adminのguaradを作成し、adminでログインしている場合(認証されている場合)には、adminが入ります。

array:4 [▼
   "login_admin_XXXXXXXXXXXXXXXXXXXXXXXXX" => 1
 ]

User / Admin 複数のGuardでログインしている時

では、User、Admin複数のGuardでログインしている場合はどうなっているでしょうか。

同じく、/testへ遷移してみます。

"login_users_XXXXXXXXXXXXXXXXXXXXXXXXX" => 1
"login_admin_XXXXXXXXXXXXXXXXXXXXXXXXX" => 1

両方のguard, session情報が含まれていることがわかります。

Laravelリーレション先のデータ個数を集計 / hasMany

Laravelのeloquentは強力なORMです。

例えば、hasManyでリレーション先につながってデータの個数を集計して、オブジェクトへ返してくれる方法があります。

Modelでリレーション記述
    public function drinkNumber()
    {
        return $this->hasMany(Join::class, 'drink_id', 'id');
    }
modelからリレーション先を自動集計したデータをオブジェクトへ
    $drinks = Drink::withCount('drinkNumber')->where('status', 1)->get();

これで、$drinksの中には、Drink Modelのオブジェクトに加えて、集計したデータも一緒に含まれます。

カラム名は下記のルールで、名称付けられます。

リレーション名_count

ngrokを利用して、Line Messaging APIのWebhook検証を「成功」

LINE公式アカウントで、チャットボットを作成する際に必要になるWebhook。開発中でも、httpsでのレスポンスが求められるため開発中断してしまう方もいらっしゃるかもしれません。

前提:
今回は、Laravelを利用してwebhookの処理を実験していきます。
LaravelのInstallや、処理内容については説明を省略します。
pcはmacを利用しています。

ngrokを利用すれば、開発環境(ローカルPC)からでも、Webhookをhttpsで受け付けるエンドポイントを設定することが可能です。また、ランダムURLで問題なければ無料で利用でいることも魅力です。

①:ngrokとは

ngrokとは、ngrokで生成したURLにきたリクエストを、別のエンドポイントへ流してくれるサービスです。
今回の場合でいうと、ngrokで指定したURLにリクエストが合った場合に、ローカルホストのエンドポイントへ流してくれます。

ngrokのサービス: https://ngrok.com/

②:ngrokの設定

非常に簡単な設定で利用を開始できます。

ngrokにsign upして下さい。

https://dashboard.ngrok.com/get-started/setup

macの場合

②-1:Download ngrok

ローカルPCへ

②-2:Unzip to install

zipファイルを回答します。

unzip /path/to/ngrok.zip
②-3:Connect your account

authtokenを利用して、権限認証します。

ngrok authtoken {//自分のauthtoken}
②-4:Fire it up

ngrokの起動です。

ngrok http 80

これで、ターミナル上にngrokが立ち上がります。

②-5:ngrokでアクセス

Forwardingになっているアドレスが、利用可能なアドレスです。

③:webhookでレスポンスを返す処理を作成

Laravelで、ルーティングと、Postの処理を記述していきます。

③-1:ルーティング設定 web.php

// LINE メッセージ受信
Route::post('line/webhook', [LineWebhookController::class, 'webhook'])->name('line.webhook');

③-2:Controllerを設定 web.php

class LineWebhookController extends Controller
{
    public function webhook(Request $request) {
        return 'ok';
    }
}

Webhookが正常に起動するかを確認するための実験なので、Postの処理は一番簡単なレスポンスを記述

④:LineのWebhook設定にURLを適用

https://0a62-39-110-209-109.ngrok.io/line/webhook

上記のように設定します。

「検証」ボタンをおして、成功が返ってくれば成功です。

ngrokを利用して、Webhookのテストをすることが出来ました。

⑤:Line Webhookをngrokが利用出来ない??

https://www.line-community.me/en/question/5f07c0fb851f74ab9c18e8dc/ngrok%E3%81%A7%E5%A4%96%E9%83%A8%E5%85%AC%E9%96%8B%E3%81%97%E3%81%9Furl%E3%81%A7webhook%E6%A4%9C%E8%A8%BC%E3%82%92%E6%88%90%E5%8A%9F%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84?sortby=newest

上記のようなコメントがありましたが、2022年4月時点で利用は出来ました!

HTTP ERROR 500|Laravelを初めて本番環境(EC2)に初アップ時の対応

EC2にgit cloneでLaravelのプロジェクトを移行、サーバーリクエストした際にHTTP ERROR 500が発生しました。

500エラーは様々な要因があるようです。下記を参考。

https://knowledge.cpi.ad.jp/other/281/

自分の場合は、非常に単純で、 .envファイルを作成していなかったから….

ファイルを作成すると、アクセスできました。( 別のディレクトリ権限のエラーが出ましたが )

Laravelのpost時に、URLをControllerへ送付する方法

laravelのget時にURLのパラメーターを送付することはよくあると思います。

では、Postの際はどのようにするのでしょうか??

まずは、データを引き渡すformから。

<form method="POST" action="{{ route('route名', ['param' => request()->path()] ) }}">
</form>

ポイント①:
actionのから変数を渡す方法です。
詳細はこちらを確認。LaravelでGET,POSTにパラメーターを追加して、渡す方法・受け取る方法

ポイント②:
現在のURLを取得する。今回でいう処理の 
request()->path() の部分です。

この2点から、パラメーターをControllerへ渡すことができすます。

Contollerでのパラメーターの受け取り方は、
$request->param で受け取ることが出来ます。
※param は、post の actionで指定したkeyになるので、変更可能です。

laravelライブラリ、GoodbyCSVで日本語文字化けを解消する方法

Goodby CSVの使い方に関しては、下記を参考にして進めています。

この中で、日本語が文字化けしてしまう現象が発生しました。

修正した部分は下記です。

// 元:$config->setFromCharset("sjis-win");
$config->setFromCharset("UTF-8"); //読み込んだcsvファイルの文字コード

問題はファイルの読み込む文字コードの問題でした。
PCのOSはmacです。この場合、UTF-8で読み込む必要がありました。
(Windowsの場合はsjis-winで問題ないと思います。)

laravel の仕組みと使い方

laravel7?? から、laravel, viewsの作り方が変わりました。

それまでは、@extends(”)・@section(”) などで、viewsを構築していたと思います。

基本的な考え方は、そこまで変化はありません。
より簡単に、使い回せるところは使いまわし、変数を上手く組み込む。といったところです。

どのように動いているのかが、理解出来ないと取っ付きづらいと思います。
今回は、どのような仕組みで動くのを最低限理解頂けたらと思います。

① viewsの配下で、blade作成するファイル

基本形は下記です。

// html ~~~~~~

ここがlaravelのプロジェクトの中で何を呼び出しているのかというと
<x-app-layout> → views/layout/app.blade.php を呼び出しています。

@extends('layouts.app') と同じような動きです。

では、<x-slot>は、どのように動くのでしょうか。

<x-slot></x-slot>範囲内に、反映したいhtmlデータを書きます。(もちろん、phpでも)

②views/layout/app.blade.php

では、<x-slot></x-slot>のデータは、どのように反映されるのでしょうか。

それが、views/layout/app.blade.phpの中で呼び出しております。

{{ $slot }}

という呼び出しで、<x-slot></x-slot>のデータを呼び出します。

なので、ベースとなるHTMLデータは、views/layout/app.blade.phpで
baldeファイルで変更したい部分は、{{ $slot }} で分けて反映させていく。といった仕組みです。

これも、以前の@section(”)と似たような考え方かと思います。

今回は、最初の一歩で取っつきにくい部分を解説しました。
様々な活用方法があるので、また解説していきたいと思います。

Laravelのスコープを利用して、Eloquentの処理を簡略化する方法

Laravelにスコープ(scope)という機能があります。
モデルを拡張する機能です。

使用用途は、特定のモデルで繰り返し発生しうる処理に対して、
モデル内でスコープを定義することで、スコープを呼び出すだけで済みます。

例えば、下記のようにPostモデルに対して、公開中の処理が下記の2つのwhere句を必要としましょう。毎回、公開中であるたびに、記述しているのはかなり面倒くさい。

Post::where(‘is_draft’, 0)
 ->where(‘isClosed’, 0) 

こういう、いろんなところで書きそうな条件はスコープにしてしまえば、書き間違えや書き漏れがなくなります。
https://readouble.com/laravel/7.x/ja/eloquent.html#query-scopes

ModelのPost.php の中で

    public function scopePublish($query)
{
return $query->where('is_draft', 0)
  ->where('isClosed', 0);
}
  • eloquentクラスに scopeXxxxxxでメソッドつくるとローカルスコープを作れる
  • そこに条件を書いておく

そうすると、呼び出し元では、

// 変更前
$searchArticles =  Post::where('is_draft', 0)
            ->where('isClosed', 0)
            ->where('lovesex' , $request->lovesex)// 変更後(スコープを利用)
$searchArticles =  Post::publish()
            ->where('lovesex' , $request->lovesex)
  • eloquentクラスに書いた scopeXxxxxxメソッドの Xxxxx 部分で呼び出し可能になる
// is_draft が0、かつ isClosed が0のデータ
RecomendArticle::where('is_draft', 0)
            ->where('isClosed', 0)

って読みづらかったものが

// 公開中のもの
Post::publish();

と無駄な記述も減らすことが可能です。