Lambda on Laravel on VueJs with Dynamodb する

[”AWS Lambda で Laravel を動かしてみた”をやってみた](https://qiita.com/ikegam1/items/b96a496751d448fffe6c)
と
[リクガメのおウチの温度/湿度をモニターしてawsに投げるのを1000円くらいでやる on arduino](https://qiita.com/ikegam1/items/8edcf5f4327226848ee8)
の続編的なやつです

センサーデータがdynamodbにガシガシ入ってきてるので、それをフロントで見えるようにしましょう。

##環境

- Amazon Linux 2(ec2) Linux 4.14.88-88.73.amzn2.x86_64
- php7.2
- laravel 5.7.19
- aws lambda + lambda layer + api gateway

前回、```/var/task```にlaravel一式を置いてしまいました。lambda layerのパッケージ落としてきてlocalでdocker runみたいな事ができたらいいんだけど、ひと手間ふた手間じゃできなそうだ。
ローカルでartisan serveして開発すすめよう。
というわけで、ec2にポート8000番を通してやります。念のため自分のIPアドレスだけ通すように。

なお、この前作ったスポットインスタンス。

<img src="https://qiita-image-store.s3.amazonaws.com/0/308709/f8bf3674-93ad-db90-294d-65c78fc8a6bb.png" width=50% />

**Saving71%**ですってよ奥さん。こんなお買い得なのか。

・・ちょっと脱線しちゃいました。
ポート8000番だ。セキュリティグループに自分用に22番空けてるやつがあったのでそこに追加しました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/308709/2f82f491-8210-8155-a998-81670c323356.png" width=50% />

そしてec2の```/var/task```で```php artisan serve -host 0.0.0.0 &```ってやったらブラウザでlaravel見れました。

## Dynamodb

まずはDynamodb使うとこからいきましょうか。
ここが参考になる。

https://tech.willgate.co.jp/entry/2018/02/28/134537

### まずはbaopham/laravel-dynamodb
https://github.com/baopham/laravel-dynamodb

```
$ composer require baopham/dynamodb
$ vi config/app.php <- 'providers'に追加
$ php artisan vendor:publish

 Which provider or tag's files would you like to publish?:
  [0 ] Publish files from all providers and tags listed below
  [1 ] Provider: BaoPham\DynamoDb\DynamoDbServiceProvider
  [2 ] Provider: BeyondCode\DumpServer\DumpServerServiceProvider
  [3 ] Provider: Fideloper\Proxy\TrustedProxyServiceProvider
  [4 ] Provider: Illuminate\Foundation\Providers\FoundationServiceProvider
  [5 ] Provider: Illuminate\Mail\MailServiceProvider
  [6 ] Provider: Illuminate\Notifications\NotificationServiceProvider
  [7 ] Provider: Illuminate\Pagination\PaginationServiceProvider
  [8 ] Provider: Laravel\Tinker\TinkerServiceProvider
  [9 ] Tag: config
  [10] Tag: laravel-errors
  [11] Tag: laravel-mail
  [12] Tag: laravel-notifications
  [13] Tag: laravel-pagination
 > 1

Copied File [/vendor/baopham/dynamodb/config/dynamodb.php] To [/config/dynamodb.php]
Publishing complete.
```

.envに下記を追記します。

```
$ echo DYNAMODB_CONNECTION='"${DYNAMODB_CONNECTION}"' >> .env
$ echo DYNAMODB_KEY='"${DYNAMODB_KEY}"' >> .env
$ echo DYNAMODB_SECRET='"${DYNAMODB_SECRET}"' >> .env
$ echo DYNAMODB_DEBUG='"${DYNAMODB_DEBUG}"' >> .env
$ echo DYNAMODB_REGION="ap-northeast-1" >> .env
```

今回の環境はec2でiamロール設定済なのでこうします

```
$ export DYNAMODB_CONNECTION=aws_iam_role
```

labmdaの時はアクセスキー認証にしようかな。

### ページ追加
一回接続の確認したいのでcontrollerとかmodelとか作ります。

```
$ php artisan make:controller Dht22Controller 
$ php artisan make:model Models/Dht22
```

下記のviewとmodelを作ります。

``` dht22/index.blade.php
<h1>{{ $title }}</h1>
<p>{{ $body }}</p>
```

``` app/Models/Dht22.php
<?php

namespace App\Models;

use Baopham\DynamoDb\DynamoDbModel as Model;

class Dht22 extends Model
{
    protected $table = 'kamekusa_dht22';

    protected $primaryKey = 'id';

    protected $compositeKey = ['id', 'expire'];
    
    public $timestamps = false;

    protected $fillable = [
        'id',
        'expire',
        'payload',
    ];
}
```

``` routes/web.php
<?php
Route::get('/', function () { return view('welcome'); });
Route::get('/dht22', 'Dht22Controller@index');
```

``` app/Http/Controllers/Dht22Controller.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Dht22;

class MonitorController extends Controller
{
    public function index()
    {
       $dht22= new Dht22();
       $datas = $dht22->all();
       $datas = json_encode($datas);
       return view ('dht22.index', ['body' => $datas, 'title' => 'Hello Lambda on Laravel with Dynamo!']);
    }
}
```

こうなりました。

![39.png](https://qiita-image-store.s3.amazonaws.com/0/308709/14af61f1-e23a-6b33-aac4-d68d345acfac.png)

ただ、$dht22->all();ってやると```/vendor/aws/aws-sdk-php/src/DynamoDb/Marshaler.php```のunmarshalValueのとこで```Deprecated: The each() function is deprecated. This message will be suppressed on further calls```って出て困ったので取り急ぎforeachに置き換えました。
eachはphp7.2から非推奨なんですね。ホストはphp7.2にしてたのでちょうどひっかかったか。
というか今、最新のソース見たら直ってました。

## Vue.js

ではお次はVue.js。

[LaravelからVue.jsを使う最短レシピ](https://qiita.com/fruitriin/items/e0f2c9aa035c3ff2c874)

最短でやりたいです。

```
sudo amazon-linux-extras install epel
sudo yum install -y nodejs
$ node --version
v6.14.3
$ npm --version
3.10.10
```

おもむろにnodejsをいれてみる。ちょっと古い気がするけどどうしたもんか。とりあえず進めてみるが、```npm install```は無事完了。

で、最短でやるやつのレポジトリを参考にさせていただきつつ進め、なんとか表示はできました。細かい所は適当ですが。

![40.png](https://qiita-image-store.s3.amazonaws.com/0/308709/d3fa4d8c-11c9-b925-d954-12801b14cde1.png)

ちゃんと日付順に並べてグラフ出したりはしたいけどひとまずはここまでで。

vueのcomponentsはこんな感じになりました。最低限な感じですが。

``` ExampleConponent.vue
<template>
    <div class="container">
      <div class="row">
        <div class="col-md-12 jumbotron">
           <h1>温度と湿度を表示するLambda on Laravel</h1>
        </div>
      </div>
      <div class="row">
        <div class="col-md-12 float-right">
          <div class="gtn-group">
            <span class="group-btn">
              <button class="btn btn-success" type="button" @click="getAll()">読みこむ </button>
            </span>
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-md-12">
          <table class="table table-striped">
            <thead class="thead-dark">
              <tr>
                <th>id</th>
                <th>expire</th>
                <th>温度</th>
                <th>湿度</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="data in datas" v-bind:key="data.id">
                <td>{{data.id}}</td>
                <td>{{data.expire | moment("YYYY/MM/DD h:mm:ss a")}}</td>
                <td>{{data.d1}}℃</td>
                <td>{{data.d2}}%</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
</template>

<script>
    Vue.use(require('vue-moment'));

    export default {
        data(){
            return {
               datas: []
            }
        },
        methods:{
            getAll: function () { 
                axios.get('/api/dht22').then((res)=>{
                    let _datas = res.data
                    this.datas=[]
                    for (let d of _datas) {
                        if ('payload' in d){
                            console.log(d.payload);
                            this.datas.push(d.payload)
                        }
                    }
                })
            }
        },
        created(){
            const self = this
            self.getAll()
            setInterval(function() {self.getAll()}, 60*1000)
        }
    }
</script>
```

その他のソース。
https://github.com/ikegam1/Lambda-on-Laravel-on-VueJs-with-Dynamodb

## Lambda
最後にLambdaに上げる。
```npm run prod```して、sam cli叩いてさくっと終わるつもりが・・

![41.png](https://qiita-image-store.s3.amazonaws.com/0/308709/73b3017a-1ea0-e7f6-36c0-cc2392d50de7.png)

おうふ。。そっかcssとかjsとかlambda経由じゃアクセスできんな。。cloudfront噛まつつ、S3に静的コンテンツ上げて振り分けて、ってやんないといけないのかな。でもまあそこまでしてlaravelでやる必要もないような。。
というわけでとりあえず動くところまではやる。

やったこと。

- public/css/app.cssをwelcome.blade.phpにインラインで埋め込んだ
- public/js/app.jsをwelcome.blade.phpにインラインで埋め込んだ
- api/dht22のパスを/Prod/api/dht22に直した
- api gatewayでapiリソースとその配下にdht22リソース作った
- sam cli用のtemplate.ymlにDYNAMODB_KEYとかのenvironmentを追記した

<img src="https://qiita-image-store.s3.amazonaws.com/0/308709/0801b20b-c42f-5118-39eb-fe7d05859306.png" width=50% />

というわけでなんとか動きました！ギリギリサーバレスです。

![43.png](https://qiita-image-store.s3.amazonaws.com/0/308709/d33683d9-db98-cbb6-37ff-377325433ec4.png)