Shopify 用のプライベートアプリを作ってみた

## Shopify アプリとは

Shopify アプリは、Shopify にインストールして利用するアプリのこと。インストールするとか書いているけど、実際には、Shopify とは別のサーバーで独自に動かしておく Web サービスを指す。

このアプリは、プライベートアプリと公開アプリがあり、公開しているアプリは誰でも使える(無料/有料あり)し、自分で使ったものを公開して、有料にすればお金を稼ぐこともできる。

今回はプライベートアプリの説明だけ。

よく分かってないけど、これとは別に [Embeded App SDK](https://help.shopify.com/api/sdks/shopify-apps/embedded-app-sdk)ってのがある。こっちは Shopify の一部として動くっぽい。

## 何ができるのか

入金完了後に、外部の配送システムに配送依頼投げたいとか、購入情報を購入完了のタイミングで、外部サービスに投げたいとか。

公開アプリには、デジタルダウンロードするためのものや、配送、在庫周りやレポート、マーケティングなどいろいろある。[Shopify のアプリストア](https://apps.shopify.com/)で公開アプリは確認できる。

## 背景 

運用している Shopify ストアで何かイベントがあった場合に、そのイベントをトリガーに外部処理を呼び出すとかしたかったので、どうやってやるのか調べてみた。(基本、ドキュメントに全部書いてあるけど、日本語ないので参考になるかも）

具体的な利用方法としては、入金完了後に、外部の配送システムに配送依頼投げたいとか、購入情報を購入完了のタイミングで、外部サービスに投げたいとか。

これを実現する方法として、Shopfiy では以下の2つ方法があると思っている。

- Webhook
- Shopify アプリ

基本的に仕組みは同じ感じで、Shopify が予め用意しているフックポイントがあるので、そこに設定をしていく。

利用できるフックポイントの Webhook のイベントの種類は以下にある。
[Shopify の Webhook のイベントとフックポイント](https://help.shopify.com/api/reference/webhook)

注文に関するもの(注文完了や支払い完了、配送）などから、商品作成などかなりたくさんある。

で、そのポイントに対して、上記で説明した３つの方法は以下のような挙動を取れる。

- Webhook: 指定した URL にポストリクエストが飛ぶ。Body は、JSON or XML。管理画面で設定する。
- Shopify アプリ: 上記の Webhook を受け付けるエンドポイントを用意しておくと、それぞれのタイミングでリクエストが飛んでくる。

## Webhook

Webhook は、管理画面で、どのイベントを利用するか選択し、宛先の URL とボディを XML か JSON を選択するだけなので、利用は非常に簡単。

利点は、設定が簡単なので、すぐ使える。ただし、当たり前だけど、受け側を用意する必要がある。

欠点は、URL しか設定できないので、受け側が認証の仕組みを持っているものだと、間に中間の仕組みをかますか、受け側で認証の仕組みを使わないエンドポイントを作る必要がある。(ちなみに、この場合、受け側でリクエストがShopifyから来た正当なものかチェックする必要があるかと思うのが、そのチェック方法については、[こちら](https://help.shopify.com/api/getting-started/webhooks#verify-webhook)に書いてある。)

Webhook を試してみたい方は、[Shopify の Webhook を試してみる](http://qiita.com/kumatronik/items/982d4c5faa1c8a4d41ae)をご覧ください。

詳しい使い方は、[こちら](https://help.shopify.com/api/getting-started/webhooks)を見てください。英語だけど。


## Shopify アプリ

こちらは最初に説明したように、Web アプリとして開発、運用するものである。アプリのエンドポイントを Shopify に設定しておくと、各イベントタイミングで、Shopify からリクエストが飛んでくる。ので、飛んできたら、好きに処理できる。受け取れる内容はたぶん、上記の Webhook と同じ。

利点は、Webhookの欠点の裏返しだが、好きな処理ができるので、認証付きのサービス呼出しなども好きにできる。

欠点は、独自にアプリを開発、運用する必要がある。あと、パートナーにならないと独自アプリの追加ができないこと。

## Webhook と Shopify アプリのどっちを使うか

まとめると、Webhook を使うか、Shopify アプリを作るかの判断は、受け側に Shopify 用のエンドポイント(Shopify 依存のロジック）を用意していいんだったら、Webhook の方がコスト低いと思う。既存のエンドポイントは変えたくないし、Shopify 依存のコードは持ち込みたくないって場合は、Shopify アプリを開発するって感じになかと思う。

---

## Shopify (サンプル)アプリの作成

前置きが長くなったけど、こっからこの記事の本題。ということで、今回は、Shopify アプリを作ることにしたので、具体的な手順を説明していく。

（といっても、手順はほぼ [公開 Shopify アプリの構築](https://help.shopify.com/api/tutorials/building-public-app) (英語)の内容のままだけど）

**今回試した環境**
- Ruby 2.3.1 + Sinatra 2.0.0 (上記のサンプルと同じ)
- [ngrok](https://ngrok.com/) : トンネルサービス(ローカルサービスをインターネット越しに一時的に呼び出せるようになる)
- OS: Mac

**事前準備:**
- Shopify のアカウントがあること
- Shopify のパートナーアカウントがあること (これがないとアプリを登録できない）
- Ruby、Bundler が使える状態
- Shopify ストアで物が買える状態にあること

**主な手順**

1. サンプルアプリの作成
2. サンプルアプリの公開
3. Shopify パートナーダッシュボード上でアプリ情報の登録と認証情報の取得
4. アプリに設定を追加
5. ストアに Shopify アプリをインストール
6. 動作確認

### 1 アプリの作成

1: `mkdir shopify_sample_app`
2: `mv shopify_sample_app`
3: `bundle init`
4: Gemfile ファイルに以下を追加。

```
gem "sinatra"
gem "shopify_api"
gem "httparty"
gem "dotenv"
```
5: `bundle install --path vendor/bundle`
6: `touch app.rb`
7: app.rb に、[この内容をコピー](https://github.com/Shopify/example-ruby-app/blob/master/01%20Getting%20Started/app.rb)。
8: `touch .env`
9: `.env` を開き、以下を入力。値は後で取るので、とりあえず以下のまんまとする。

```
API_KEY=YOUR_API_KEY
API_SECRET=YOUR_SECRET_KEY
```
10: `bundle exec ruby app.rb` 
    ちゃんと動くか、起動してみる。ブラウザで、`http://localhost:4567` にアクセス。なんとなく動いてそうなら、OK。

開発自体は一旦終了。次は、ローカルアプリを外部に(一時的に)公開する。

### 2. サンプルアプリの公開

ローカルアプリをとトンネルサービス(ngrok)を使って、一時的にインターネット上に公開する。

1. [ngrok をダウンロード](https://ngrok.com/)
2. ダウンロードしたディレクトリに移動。
3. OSX または、Linux の場合は、`./ngrok http 4567` で起動。Windows の場合は、`ngrok http 4567`。
4. 起動すると、ngrok が立ち上がり、`Forwarding`ってとこに、外部からアクセス可能な URL が表示される。これが、Shopify 側に今回設定する URL となる。例: `http://ac2a51a0.ngrok.io`
5. ブラウザで一旦、このアドレスにアクセスし、localhostの場合と同じ結果か確認する。

これで、Shopify からのリクエストを受信できる体制が整った。
次は、Shopify にアプリ情報を登録し、1の手順で設定していなかったアプリの認証情報を取得する。

### 3. Shopify パートナーダッシュボード上でアプリを登録

Shopify で独自のアプリを利用するには、パートナーダッシュボードで、アプリ情報を登録する必要がある。

1. [パートナーダッシュボード](https://partners.shopify.com/organizations)にログイン。
2. `Development stores` をクリック。
3. `Apps` をクリック。
4. `Create app` をクリック。
5. アプリ名と URL (`https://#{app_url}>/giftbasket/install` を入力。`app_url` は、ngrok が発行した URL に置き換える。例: `https://ac2a51a0.ngrok.io/giftbasket/install`
6. `App Info` タブを開き、Whitelisted redirection URL に以下を追加。(既に、`xxx/install`があるので、改行して追加する)`https://#{app_url}/giftbasket/auth`。上記と同じで、app_url は置き換えること。
7. 下にスクロールし、`App credentials` にある `API key` と `API secret key` をコピーする。(secret key は、`Show` をクリックし、内容を表示する)
8. 画面上部の **Save** ボタンをクリック。

App Store の画面が表示されるが、一旦おいておく。(後で戻ってくるので、画面は閉じずにおいておく)


### 4. アプリに設定を追加

#### 4.1 認証情報の設定

3で、アプリの認証情報(APIキーと API Secret)をコピーしたので、それを 1で作成した `.env` ファイルの値部分に設定する。

例:

```
API_KEY=123e443dfddfva43l3l
API_SECRET=dafd33ljdfa0j43dl
```

#### 4.2 アプリのURLを設定

`app.rb` 内の `APP_URL` の値を公開URLに置き換える。

例:

```
APP_URL = "ac2a51a0.ngrok.io"
```


#### 4.3 アプリの起動

設定したら、アプリを起動する。

```
bundle exec ruby app.rb
```

これでアプリ側はすべて終了。次は、このアプリをストアで利用できるようにする。

### 5. ストアに Shopify アプリをインストール

これまでで、Shopify アプリがストアから利用できるようになりました。ここで、手順3の最後で、置いておいた作成したアプリの設定画面に戻ります。(閉じてしまった方は、再度パートナーダッシュボードにアクセスし、**Apps** > 作成したアプリ名をクリックします）

1. アプリの設定画面右上の `Create App Store listing` をクリック。
2. **View app listing** をクリックします。これでアプリストアにアプリが読み込まれます。
3. **Get** をクリックすると、アプリをストアにインストールします。(このとき、認証情報が間違っていたりすると、エラー画面が表示されます）
4. 成功すると、ストア画面のアプリ画面に遷移します。(まだインストールは完了していません。)
5. 画面右したの、`Install unlisted app` をクリック。
6. インストールが成功すると、**Bulk editor** 画面が表示されます。(これは、app.rbの処理で成功時のリダイレクト先がその画面になっているため）

これで無事、ストアで独自アプリが使えるようになりました。

### 6. 動作確認

それでは、正常に動くか試してみます。
今回のアプリは、注文が作成されたタイミングで、Webhookが発行されます。よって、ストアで普通に商品を入れ、チェックアウトを完了してください。チェックアウト完了のタイミングで、注文(Order)が作成されます。
このタイミングで、起動している Sinatra のログを確認していると、以下のようなログが出力されていれば、無事呼ばれています。

```
127.0.0.1 - - [23/Aug/2017:01:05:56 JST] "POST /giftbasket/webhook/order_create HTTP/1.1" 200 43
- -> /giftbasket/webhook/order_create
```

-----

以上で終わりです。

`app.rb` の中身について何も解説してませんが、知りたい方は、[こちら](https://help.shopify.com/api/tutorials/building-public-app#step-4-building-your-application) をご覧ください。


これはあくまでサンプルアプリなので、本番で利用する場合は、OAuthの検証をもっとちゃんとやったほうがいい(`omniauth-shopify-oauth2` geｍ の利用を推奨）と Shopify は言っています。