Shopifyアプリを Amazon EventBridge と統合してみる #shopify
こんにちは、クラスメソッドの岡です。
今日2020/12/17の16:00から「AWSとReactで始めるShopifyアプリ開発」が開催されます。
この記事は3つ目のセッション「EventBridgeでAWSとShopifyの統合」での統合手順の解説ブログとなります。
Shopifyのアカウント
まず前提の知識として、shopifyアカウントには2種類あります。
- ショップアカウント
- ショップを運営・販売するマーチャントが利用するアカウント
- パートナーアカウント
- shopifyパートナーがShopifyアプリを開発・販売するアカウント
ShopifyをEventBridgeと統合するには パートナーアカウント が必要になります。
こちらから作成してください。
パートナーのストア管理の画面からストアを追加すれば無料で検証ができる開発ストアとしてショップが利用できます。
Shopifyアプリ
Shopifyアプリには以下の3種類があります。
- カスタムアプリ
- 単一のストアでインストールできるアプリ
- 公開アプリ
- Shopifyアプリストアで販売できるアプリ
- プライベートアプリ
- ストア管理画面上で作成されるアプリ
プライベートアプリではEventBridgeとは統合できません。今回は検証で1店舗のイベントデータをEventBridgeに渡したいので、カスタムアプリを構築します。
パートナー管理画面の操作
開発ストアまで用意できている前提で進めます。
1, パートナーアカウントのアプリ管理画面から「アプリを作成する」をクリック
2, 今回はカスタムアプリを選択します。
3, URLはあとで用意するので一旦仮で入れてそのまま作成します。
Shopifyアプリを作成する
Shopifyアプリをストアにインストールする際に設定したURLがhttpsでホストされている必要があります。
しかし今回はEventBridgeと統合するだけで画面も必要ないし常時稼働している必要もありません。今回はインストール用にバイパスだけ用意します。
Shopify App CLIで、一番手軽な方法「Shopify App CLI」でShopifyアプリを作成します。
ちなみにShopify App CLIのコマンドを使ってデプロイした場合はherokuにデプロイされます。しかしここでは Admin API が実行できる環境を準備したいだけなのでデプロイはせずにngrokでローカルサーバーに対してhttpsでアクセスできるようにします。
インストール
$ brew upgrade $ brew install shopify-cli
アプリを作成
shopify create
を実行します。
$ shopify create ? What type of project would you like to create? (You chose: Node.js App) ? Appname > shopify-devio-app ? What type of app are you building? (Choose with ↑ ↓ ⏎, filter with 'f') 1. Public: An app built for a wide merchant audience. > 2. Custom: An app custom built for a single client.
今回はNode.js Appを選択、アプリ名「shopify-devio-app」、Shopifyアプリの種類→カスタムアプリとそれぞれ入力します。
プロジェクトフォルダが作成されるので、移動します。
$ cd shopify-devio-app
.envのファイルが生成されているので、それぞれ自分の情報に書き換えます。
- SHOPIFY_API_KEY: アプリ詳細画面に表示されるAPIキー
- SHOPIFY_API_SECRET: アプリ詳細画面に表示されるAPIシークレット
- SHOP: アプリをインストールするストア
- SCOPES: アプリ内で許可するスコープ(write_products,write_customers,write_draft_orders)
- HOST: アプリのURL, serveコマンド実行時に更新される
ngrokでローカルサーバーを起動
shopify serve を実行するとngrokで起動します。
$ shopify serve ✓ ngrok tunnel running at https://hogehoge.ngrok.io ✓ .env saved to project root ? Do you want to update your application url? (You chose: yes) ✓ Whitelist URLS updated in Partners ⭑ To install and start using your app, open this URL in your browser: https://hogehoge.ngrok.io/auth?shop=developers-io-store.myshopify.com
開発ストアにアプリをインストール
serveコマンド実行時にインストールリンクが発行されているので開発ストアにサインインした状態でアクセスすると確認画面に遷移します。
https://hogehoge.ngrok.io/auth?shop=developers-io-store.myshopify.com
開発ストアのアプリ管理内にアプリの画面が表示されました。
ここまでで、EventBridgeと統合するためのアプリの用意ができました。
EventBridgeにパートナーイベントソースを作成
ここからが本題です。
パートナーダッシュボードに戻り、アプリ設定の画面を再度開きます。
イベントサブスクリプションの項目にEventBridgeのソースを作成するボタンがあるのでクリック
アカウントIDとリージョン, ソース名を入力して作成します。
EventBridgeのイベントバスと関連付け、ルール作成
イベントバスと関連付け
EventBridgeのコンソールを開いてみると、アプリID/ソース名がパスになったパートナーイベントソースが作成されています。
「イベントバスと関連付ける」をクリックします。
ステータスがアクティブに変更されたらOKです。
ターゲット用にLambdaを作成
イベントをログ出力するだけのLambdaを用意しておきます。
exports.handler = async (event) => { console.log(event); const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
ルールの作成
左ペインからルールを選択して、作成したイベントバスを選択、「ルールを作成する」をクリックします。
任意のルール名
ターゲットにLambdaを選択します。
ルールが作成できたらLambdaのトリガーにShopifyのアイコンが表示されます。
ここまででEventBridge側の準備ができました。
ただこのままだとShopifyアプリ→EventBridgeへイベントが届きますがShopifyショップ→ShopifyアプリへのwebhookはShopifyのAdmin APIで登録する必要があります。
ShopifyのAdmin APIでwebhook登録
Admin APIはOAuth 2.0の authorization code grant flow を使って認証します。
なのでアクセストークンの前に認可コードを取得する必要があります。
認証コードを取得
https://{shop}.myshopify.com/admin/oauth/authorize
に対してリクエストを送ります。
クエリパラメータに以下を付与します。
- client_id: ShopifyアプリのAPIキー
- scope: 要求するスコープ()
- redirect_uri: ShopifyのリダイレクトURL
- state: 一意の文字列
- grant_options[]: オフラインかオンラインの設定(オプション)
実際には以下のようなURLになります。
https://developers-io-store.myshopify.com/admin/oauth/authorize?client_id=xxxxx&scope=write_products,write_customers,write_draft_orders&redirect_uri=https://hogehoge.ngrok.io/auth&state=5b407360-4009-11eb-9c4e-acde48001122
ショップアカウントでサインインしたブラウザでURLにアクセスすると、インストール時と同じように権限を確認ページに遷移します。
アプリを更新するを押すと、リダイレクトURLのクエリパラメータに code
が含まれて返ってくるのでこのコードを使ってアクセストークンを取得します。
アクセストークン取得
ここではREST APIで実行します。
https://{shop}.myshopify.com/admin/oauth/access_token
に対してPOSTリクエストを送ります。
$ curl -X POST -H "Content-Type: application/json" https://developers-io-store.myshopify.com/admin/oauth/access_token -d "$(cat <<EOS { "client_id": "APIキー", "client_secret": "APIシークレット", "code": "上で取得した認証コード" } EOS )" | jq .
webhook登録
エンドポイント
address
には EventBridge の パートナーイベントソースの ARNを入力してください。
$ curl -X POST -H "Content-Type: application/json" -H "X-Shopify-Access-Token: xxxxx" https://developers-io-store.myshopify.com/admin/api/2020-07/webhooks.json -d "$(cat <<EOS { "webhook": { "topic": "products/update", "address": "arn:aws:events:ap-northeast-1::event-source/aws.partner/shopify.com/9999999/shopify-devio-app", "format": "json" } } EOS )" | jq .
以下のようにレスポンスが返ってきます。
{ "webhook": { "id": 123456789, "address": "arn:aws:events:ap-northeast-1::event-source/aws.partner/shopify.com/9999999/shopify-devio-app", "topic": "products/update", "created_at": "2020-12-16T08:11:01-05:00", "updated_at": "2020-12-16T08:11:01-05:00", "format": "json", "fields": [], "metafield_namespaces": [], "api_version": "2020-10", "private_metafield_namespaces": [] } }
動作確認
ここまででShopify上にある開発ストアのイベントをEventBridgeで受け取れるようになりました。
Developers.IO Storeの商品を実際に更新して動作確認してみます。
商品の説明を追加してみます。
Lambdaのロググループに以下のようにデータが出力されています。
{ version: '0', id: 'dsofhijmcise', 'detail-type': 'shopifyWebhook', source: 'aws.partner/shopify.com/9999999/shopify-devio-app', account: '123456789012', time: '2020-12-16T15:18:57Z', region: 'ap-northeast-1', resources: [], detail: { payload: { id: 5853201367192, title: '花咲ひさきTシャツ', body_html: 'てすと', vendor: 'Developers.IO Store', product_type: '', created_at: '2020-09-29T22:52:13-04:00', handle: '花咲ひさきtシャツ', updated_at: '2020-12-16T10:18:54-05:00', published_at: '2020-09-29T22:52:15-04:00', template_suffix: '', status: 'active', published_scope: 'web', tags: '', admin_graphql_api_id: 'gid://shopify/Product/5853201367192', variants: [Array], options: [Array], images: [Array], image: [Object] }, metadata: { 'Content-Type': 'application/json', 'X-Shopify-Topic': 'products/update', 'X-Shopify-Shop-Domain': 'developers-io-store.myshopify.com', 'X-Shopify-Product-Id': '5853201367192', 'X-Shopify-Hmac-SHA256': 'efdwiqTOJJSDJcLY+wXI4=', 'X-Shopify-API-Version': '2020-10' } } }
まとめ
今回は簡易的な構成で試してみましたが、もう少し業務側のユースケースも含めたパターンを試した記事も出していこうと思います!