Shopify FlowのTrigger、Actionの作成方法

[Appify Technologies Advent Calendar 2021](https://www.notion.so/appify/Appify-Advent-Calendar-2021-aeb2651581834d589e5fe140d80513c7) の24日目の記事です。

この記事ではShopifyアプリを開発している方に向けて、開発しているShopifyアプリからShopify FlowのTriggerとActionを提供する方法について解説します。

# Shopify Flowとは
Shopify Flowは、ストアやアプリで発生した様々なイベントからタスクを自動実行するワークフローを構築するためのプラットフォームです。
例えば、カスタマーの登録がされたことを検知してそのカスタマーに対してメールを自動で送ったり、特定の注文があったら社内のSlackに通知を出したりなど、Eコマースにまつわる業務の自動化を簡単に行うことができます。
Shopify Flowは現在Shopify Plusプランでないと利用できませんが、将来的にはShopify Plusプラン以外でも利用可能になっていくそうです（[言及している動画](https://youtu.be/KgQkG_ZXs_w)）

ワークフローによりShopifyアプリ間の連携も実現することができます。
以下は、ShopifyアプリAとBをストアにインストールしているマーチャントが、アプリ間の連携をするためのワークフローを作った場合のワークフロー実行のイメージです。
![flow.drawio (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143822/008c00d2-033b-4470-5024-043db73f2f76.png)

# ワークフローの構成要素
Shopify Flowのワークフローの構成要素はTrigger、Action、Conditionの3つです。
下記ワークフローの画像を例に説明します。
このワークフローは、10万円超の注文があったときに所定のメールアドレスに自動でメールを送るワークフローです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143822/22aa7ab3-5e82-8565-dcda-b4709cb9d019.png)

## Trigger
Triggerはワークフローを開始するイベントを定義したものです。画像の左端の"Start When..."と書いてある要素になります。
画像のワークフローでは、Shopifyが提供するTriggerを使っていますが、自身が開発しているShopifyアプリからも提供することができます。
その場合、自身のShopifyアプリのシステムからShopifyのAPIに向けてリクエストを送ることでイベント（Trigger）が発生したことをワークフローに伝えることができます。
Triggerが発火すると、定義されたワークフローに沿ってタスクが実行されていきます。

## Action
Actionは発生したTriggerに対して何を実行するかを定義したものです。画像の右端の"Do This..."と書いてある要素になります。
Actionも自身が開発しているShopifyアプリから提供することができます。
Actionには、Actionが実行されたときに呼び出すURLを指定することができ、これに自身のサーバのエンドポイントを指定することで任意のイベント（Trigger）から自身のアプリの処理を実行することができます。

## Condition
ConditionはActionの実行条件を定義したものです。画像の中央の"Check If..."と書いてある要素になります。
これはShopifyアプリから提供するものではなく、ワークフローを作成するマーチャントがワークフローの編集画面で必要に応じて追加するものです。
起動したTriggerが持つプロパティの値に応じて条件分岐をしてActionを実行することができます。
画像では、注文作成時のTriggerに対して、Triggerのプロパティ`Amount`が100000を超える場合にだけActionを実行するようになっています。

# Triggerの作成
Shopify partners画面からアプリ管理＞アプリの詳細＞拡張機能＞作成＞Flow から作ることができます。

## 認証
Triggerを起動するときに送るリクエストの認証方法はShopify Admin APIの呼び出しと同じなので[Admin APIの認証方法](https://shopify.dev/api/admin-graphql#authentication)に従ってください。

## プロパティの設定
Triggerを起動するときにShopify Admin APIにリクエストを送るのですが、このときリクエストにプロパティを含めることができます。
このプロパティは、Actionから利用することができます。

**カスタムプロパティ**
型とプロパティ名を指定することができます。プロパティ名は、[ドキュメント](https://shopify.dev/apps/flow/triggers#property-names)によると"City location"のようにセンテンスケースで記述することが推奨されています。

**Shopifyが用意しているプロパティ**
カスタムプロパティ以外にもShopifyが用意しているプロパティがあり、これは型やプロパティ名は固定です。
顧客・注文・商品から選択することができます。
これらは、Trigger起動のリクエストに顧客ID・注文ID・商品IDを指定することで、ActionからそれぞれのShopify上のオブジェクトのフィールドを利用できます。
例えば、注文IDを指定してTriggerを起動したら、ActionからOrder.createdAtやOrder.cancelReasonを利用できるようになります。

## Triggerを起動する方法
自分のShopifyアプリのTriggerを起動するには、ShopifyのAdmin APIのGraphQLエンドポイントにmutationリクエストを送る必要があります。
リクエストの形式は、Trigger作成画面のペイロードのプレビューから確認できます。
下記にmutationリクエストの例を記載します。


```graphql
mutation {
  flowTriggerReceive(body: "{
  \"trigger_id\": \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",
  \"resources\": [
    {
      \"name\": \"My Trigger\",
      \"url\": \"https://www.example.com/my-trigger/help\"
    }
  ],
  \"properties\": {
    \"customer_id\": 1,
    \"Used points\": 100
  }
}") {
    userErrors {
      field,
      message
    }
  }
}
```

見るとわかるように、Trigger起動はflowTriggerReceiveというmutationにbody引数に文字列を渡す形になっています。
このbody文字列の内容はTriggerに設定したプロパティに応じて変化することになります。
上記の例では、Shopifyが用意している顧客プロパティとNumber型の"Used points"というカスタムプロパティを指定しています。
自分のShopifyアプリが複数のTriggerを提供している場合には、`trigger_id`、`resources`、`properties`の部分をTriggerごとに変更してmutationを呼び出すことになります。

## Triggerに関する注意点
私がTriggerに関する開発をしている中で、ハマったり遭遇した事象について記載します

- Triggerのプロパティを1つも指定しない場合、リクエストを送ってもTriggerは起動しない
- Triggerに顧客プロパティを追加して、Actionで顧客プロパティの情報を使わなかったらリクエストを送ってもTriggerは起動しない
- [ドキュメント](https://shopify.dev/apps/flow/triggers#2-configure-your-web-server)にはmutationにHMACヘッダが必要と書いてあるが無くても起動できる（ヘッダ名も指定されてないので単に不要と思われる）
- Triggerの起動リクエストの送り先はAdmin APIなのでAdmin APIのレートリミットが適用される

## Actionの作成
Triggerと同様に、Shopify partners画面からアプリ管理＞アプリの詳細＞拡張機能＞作成＞Flow から作ることができます。

### Actionのタイトル設定
Actionのタイトルは、ワークフロー作成画面で表示されるActionの表示名になるとともに、Actionが起動時に送るJSONペイロードの`action_definition_id`プロパティに反映されます。

### ActionのHTTPSリクエストURLの設定
このActionが起動したときに送るPOSTリクエストの送り先を指定します。
Actionが起動されたときの処理を実装しているエンドポイントを指定してください。

### Actionからのリクエストの検証
Actionからのリクエストを受け取ったサーバで、そのリクエストが自分のShopifyアプリが提供しているActionからのリクエストであることを検証するためには、リクエストヘッダにあるHMACダイジェストを使います（[ドキュメント](https://shopify.dev/apps/flow/actions#2-configure-your-web-server)）


### プロパティの設定
Actionが受け取ることのできるプロパティを設定することができます。
これはメソッドの引数のようなもので、ここで設定したプロパティに対してワークフローの作成画面でTriggerのプロパティの値をActionのプロパティに渡したりすることができます。
プロパティに渡された値は、Actionが起動時に送るPOSTリクエストのペイロードに含まれます。
下記はPOSTリクエストのペイロードの例です。

```json
{
    "shop_id": 0,
    "shopify_domain": "johns-apparel.myshopify.com",
    "action_run_id": "xxxx-xxxx-xxxx-xxxx",
    "action_definition_id": "My action",
    "properties": {
        "CustomerID": "9999",
        "UsedPoints": "100"
    }
}
```
`properties`に自分が指定したプロパティが反映されます。
ActionのプロパティはなぜかTriggerのプロパティと違い、表示名とプロパティ名を分けることができるので表示名はセンテンスケース、プロパティ名はキャメルケース、みたいなことができます。

**注意**
プロパティの型には注意が必要です。`UsedPoints`が文字列になっていますが、これは自分で文字列としてプロパティを定義しました。
数値型にするとTriggerのプロパティを渡せなかったため、文字列型を指定しています。

# おわりに
以上がShopify FlowのTrigger、Actionの大まかな作成方法になります。
細かい説明やWebhookに関する部分については省いていますが、TriggerとActionはもう動かせていると思うので残りはドキュメントを確認して簡単に実施できるかと思います。