shopifyで在庫が切れそうな商品を通知するbotの作成

## はじめに
[この記事はShopify開発を盛り上げる Advent Calendar 2020](https://qiita.com/advent-calendar/2020/shopify-liquid) 14日目の記事です。
shopifyはデフォルトで商品が売れていき、在庫が切れると自動的に売り切れの表記になるのはありがたいのですが、
そもそも在庫が切れそうになったら教えて欲しいです。
しかしデフォルトでそういう機能が見つからなかったのでサクッと商品が売れて在庫が切れそうになったらslackに通知してくれるbotを作成しました。

## やること
1. slackのWebhookを受けるボットを用意する
2. ShopifyのWebhookを受けるサーバーを用意する
3. Webhookを受けたあとの処理の実装をする
4. Shopifyの管理画面から「商品更新」のWebhookを設定する
5. 実際に更新通知を受けてslackに通知するか確認する

やることとしてはこの程度です。とても簡単です。

## 1. slackのWebhookを受けるボットを用意する

slackの[Incoming Webhookのチュートリアル](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8)どおりにIncoming WebhookのURLを取得してください。


## 2. ShopifyのWebhookを受けるサーバーを用意する
サーバーは正直なんでも良いです。本記事ではfirebaseのcloud functionsで実装します。
AWSのAPIGatewayでも自前のサーバーにWebhookを受ける口を用意しても良いと思います。

cloud functionsの導入方法は割愛します。公式のチュートリアルにしたがって導入してください
https://firebase.google.com/docs/functions/get-started?hl=ja

## 3. Webhookを受けたあとの処理の実装をする
ここからが本題です。
Webhookの実装にあたって2つnpmでモジュールを追加しました

```
npm install shopify-hmac-validation
npm install request
```
 [shopify-hmac-validation](https://github.com/leighs-hammer/shopify-hmac-validation)を導入していますがこれはPOSTされたデータがshopifyからのものかを検証するロジックを簡略化するためにいれました。
公式にruby,php,pythonのサンプルソースコードはあるのでそちらの言語を使っている場合は参考にしてください。
https://shopify.dev/tutorials/manage-webhooks

index.jsを以下のように実装します。

```js

const functions = require('firebase-functions');
const http = require('request');
const checkHmacValidity = require('shopify-hmac-validation').checkWebhookHmacValidity
const slackWebhookUrl = "各自置き換えてください"//SlackのIncoming WebhookのURLに置き換えてください
const shopifySecret = "各自置き換えてください" //後述します


exports.webhookProduct = functions.https.onRequest((request, response) => {
    //POST出ない場合は何もしない
    if (request.method !== 'POST') {
        response.status(405).send('Method Not Allowed');
        return;
    }
    const checkHmac = checkHmacValidity(shopifySecret, request.rawBody.toString(), request.header("x-shopify-hmac-sha256"));
    //shopifyからのリクエスト出ない場合はなにもせずにreturn
    if (!checkHmac) {
        functions.logger.info("Hmac does not match", request.rawBody.toString());
        response.send("Hmac does not match");
        return;
    }
    //公開済み商品でない場合は何もしない
    if(request.body.published_at === null) {
        response.send("OK");
        return;
    }
    request.body.variants.forEach(variant => {
        //商品の在庫が1以下の場合はslackにメッセージPOSTのデータ
        if (variant.inventory_quantity <= 1) {
            http.post({
                uri: slackWebhookUrl,
                headers: {
                    "Content-type": "application/json",
                },
                json: {
                    "text": "「" + request.body.title + "」の在庫が切れそうです"
                }
            }, (error, response, body) => {
            });
        }
    })

    response.send("OK");
});
```

firebaseにデプロイします。

```
firebase deploy --only functions
```

以上でfirebase側の実装は終了です。

## 4. Shopifyの管理画面から「商品更新」のWebhookを設定する
「商品更新」のshopifyのショップ管理画面から「設定」→「通知」→「Webhookを作成」と遷移し
「商品更新」のWebhookを作成し、Webhookを受けるURLに先程deployしたfirebaseのcloud functionのURLを設定します。
![スクリーンショット 2020-12-10 16.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5398/d25c8f70-9582-2b02-3b6d-03750c6b83b6.png)
![スクリーンショット 2020-12-10 16.58.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5398/376b9107-eaaf-de27-f232-7e9ff66c39ee.png)

先程index.jsに記述のあった

```js

const shopifySecret = "各自置き換えてください"
```

この部分はWebhookのページにsecretの情報があるのでそれに各自置き換えてください
![スクリーンショット 2020-12-13 1.18.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5398/85671b7e-ab53-f652-4efc-707b9d411802.png)


## 5. 実際に更新通知を受けてslackに通知するか確認する
ここまでくれば準備完了です。あとは試しにショップで商品を購入してみましょう
在庫が1以下になったときにアラートが来るように設定しているので、商品の在庫数を2個にして購入してください。
購入後slackのWebhookに通知がくれば完成です。

![スクリーンショット 2020-12-13 1.11.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5398/5d7999c4-6f14-ca8f-b37c-fef18824798b.png)

## さいごに

shopifyのWebhookはかなり充実しています。だいたいのアクションに対してWebhookを設定できるのでまだまだ便利な使い方ができそうです。
ちなみに今回のbotは「商品更新」に設定しており、商品の注文が入ったときだけでなく管理画面から商品を更新したときもWebhookが飛んできます。なのでもともと在庫が少ないような商品は管理画面で更新しても来てしまうのでそのあたりは注文作成のWebhookなどと組み合わせていい感じに実装する必要が出てきそうです。