30代ヨワヨワエンジニアがServerlessFramework(lambda)を使ってphpでslackにapiを使用して村上春樹風に語りながら猫画像を定期的に投稿するプログラムを書いてみた

早速ですが

###**僕の上司は猫です**

なので、気まぐれで寂しがり屋な上司のためにも猫の画像を取得してslackに定期的に画像を投稿出来るように挑戦してみました。


##今回の制作背景
上司のためでもありますが、入社して6ヶ月たちapiを使って連携する事が(cronも多い）ため実装する事でapi連携がわかるのではないかと思ったのと、lambdaの話をよく聞く事が多かったのでServerlessFrameworkを使用してslackに猫画像を定期的に投稿するプログラムを実装してみました

##目次
[1.開発環境](#1-開発環境)
[2.使用したAPI](#2-使用したAPI)
[3.コードとディレクトリ構造](#3-コードとディレクトリ構造)
[4.苦労した事](#4-苦労した事)
[5.良かった事](#5-良かった事)
[6.改善点](#6-改善点)
[7.その他参考にした記事](#7-その他参考にした記事)
[8.おわりに](#8-おわりに)

#1. 開発環境
ServerlessFrameWork
Framework Core: 2.12.0
Plugin: 4.1.2
SDK: 2.3.2
Components: 3.4.0


php:7.3
bref:0.5.33

ServerlessFrameworkとは
[公式ドキュメント](https://www.serverless.com/framework/docs/)

>サーバーレスフレームワークを使用することで、オーバーヘッドとコストを大幅に削減して、サーバーレスアプリケーションを開発、展開、トラブルシューティング、および保護する

負荷やらお金を大幅削減できるらしいですね

lambdaはサーバーを用意する必要がなく、パッチ当てなどの保守作業を行わなくても良いため、利用者はインフラ管理の大部分をクラウドに任せて、開発リソースをつぎ込むことができるのがメリットのようです。
ServerlessFrameworkの中核的な存在ですね。

サーバレスアーキテクチャに関する説明が下記となります。
https://mmmcorp.co.jp/column/serverless/

#2. 使用したAPI
[TheCatApi] (https://thecatapi.com/)
[Slack] (https://slack.com/intl/ja-jp/help/articles/202026038-Slackbot-%E5%85%A5%E9%96%80)

Api導入にあたり参考にさせて頂いたQiita記事
Catapi関連（参考にさせて頂いた部分が多かったです）:https://qiita.com/nkojima/items/ac28780c5e61c6a9f999v
SlackBot関連:https://qiita.com/gkzz/items/23a7d03aeadcec341700

#3. コードとディレクトリ構造
###ディレクトリ構造
```
.
├── composer.json
├── composer.lock
├── index.php
├── serverless.yml
└── vendor
    ├── async-aws
    ├── autoload.php
    ├── bin
    ├── bref
    ├── composer
    ├── hollodotme
    ├── mnapoli
    ├── nyholm
    ├── php-di
    ├── php-http
    ├── psr
    ├── riverline
    └── symfony
```

###
```serverless.yml
service: phpapp

provider:
    name: aws
    region: ap-northeast-1
    runtime: provided

plugins:
    - ./vendor/bref/bref

functions:
    function:
        handler: index.php
        description: ''
        layers:
            - ${bref:layer.php-73}
        events:
          - sqs:
              arn:
                Fn::GetAtt:
                  - PhpQueue
                  - Arn
          - schedule: cron(0/50 * * * ? *)  # 毎日50分おき

resources:
  Resources:
    PhpQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: phpqueue
```

```index.php
<?php
declare(strict_types=1);
require __DIR__.'/vendor/autoload.php';

lambda(function ($response) {
$cat_url = 'https://api.thecatapi.com/v1/images/hogehoge'; // cat_apiのリクエストするURLとパラメータ

// curlセッションを初期化する
$curl = curl_init($cat_url);

// リクエストのオプションをセットしていく
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); // メソッド指定
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 証明書の検証を行わない
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // レスポンスを文字列で受け取る

ここまでGET
-------------------------------------------------------------
ここからPOST

// レスポンスを変数に入れる
$response = curl_exec($curl);
// JSON文字列をデコードした結果を変数にいれる
$result = json_decode($response, true);
// urlのバリューを取り出して変数にいれる
$image = $result[0]['url'];

// slack_apiのURLとパラメーター
$url = 'https://hooks.slack.com/services/hogehoge';

// 配列にキーとバリューをいれる
$message = array(
  "username"   => "ユーザー名",
  "icon_emoji" => ":slack:",
  "text" => "やれやれ\n".$image,
);

// メッセージをjson化
$message_json = json_encode($message);

// payloadの値としてURLエンコード
$message_post = "payload=".urlencode($message_json);

// curlセッションを初期化する
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url); // curlオプションを設定する
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // curl_exec()を実行時、返り値を文字列で返す。
curl_setopt($ch, CURLOPT_POST, true); // POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $message_post); // CurlPostする際に必要
curl_exec($ch); // curlを実行する
curl_close($ch); // curlセッションを終了する
});
```
lambdaでGETしたら....

![スクリーンショット 2020-11-24 1.23.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542637/eaa64ac9-df9e-efc9-440f-8348255235c8.png)

取れた！後はURLをJSONからデコードしてURLのバリューを取り出して配列に入れてエンコードして....

###結果
![スクリーンショット 2020-12-06 18.52.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542637/b6a4ca82-a044-63df-ef3f-7a8f39f98615.png)

出来た！後は50分おきに投稿されるだけ

![スクリーンショット 2020-12-06 17.51.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542637/d26c0c02-4517-7cae-cdc6-ce23d35ddda8.png)


### ドーン！！！


#4. 苦労した事
- lambdaのruntimeにphpがなかったので、customruntimeのbrefを使ったが設定に若干、てこずった。[参考にしたbrefの設定リンク](https://serverless.co.jp/blog/38/)
- jsonを一度、デコードしてから配列に変換し、その中の値を取り出して新たな配列に値を入れてエンコードする一連の作業に苦しめられた。
- 作った変数の中にどの値が入っているか毎回、dumpして今の形式がどうなっているか細かなデバッグをしながら作業した。

#5. 良かった事
- curlでGETとPOSTする基本的な動作を行う事ができた
- データをどう取ってきて、どう処理するかの一連の流れをより理解する必要がある事がわかった
- apiの一連の流れを自分で考えながら（かなり助けていただきました）実装できた事。
- GETとPOSTの関数は別にするのが通常だが、ワンライナーで試しにやってみて試行錯誤しながら出来た事。
- serverless deployコマンドだけでlambdaにdeployが出来る事を知れたのは良かった。


#6. 改善点
- 当初、laravelとphpで実装しようとしていたが、phpのみの実装に変えた(そもそもlaravelを使うならlambdaを使うメリット、デメリットやコストパフォーマンスを理解してから実装する必要がありそう）
- 今回は画像形式が文字列でslackに投稿してもslack上に画像を出す事が出来たが、本来あらゆる形式を扱えるようになる必要がある。
- やれやれしか呟けなかった。色んな種類の春樹風を呟きたかった。

#7. その他参考にした記事や簡単な用語メモ
Curl
インターネットプロトコルを使用してURLとして指定されたリソースのインターネット転送を行うツール(色んな言語で使える）
[Curlでapi] (https://qiita.com/re-24/items/bfdd533e5dacecd21a7a)
[エンコードとデコード](https://qiita.com/sisisin/items/3efeb9420cf77a48135d)
その他いろいろ
  
#8. おわりに
個人的には勉強する部分が多かったので非常にためになりました！
プログラマ歴の浅い人でも知らない技術に果敢に挑戦出来るんだぞと勇気づける事が出来れば幸いです。
一緒に住んでいるシェアハウスの住民には色々と助けてもらいました。ありがとうございました。
業務ではまだまだ戦力としては雀の涙ですが、フロントとバックエンドも全て出来る職場で自由な環境で働けているのでありがたいです。つよつよ目指して引き続き頑張ります。