Ruby on Rails × Shopify Customer API で顧客情報を操作してみる

## 概要

業務の一環でShopifyのCustomer APIを使い外部からShopify側で保持する顧客情報を操作する機会があったので、手順などについてメモ書きしておきたいと思います。

## 前提条件

- Shopify Multipass APIを用いたSSO（シングル・サイン・オン）が実装されている事。

![Untitled Diagram(11) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/bd38cfec-f437-e00e-eb69-b1eb83817588.png)

参照記事: [Ruby on Rails × Shopify Multipass APIでSSO（シングル・サイン・オン）を試してみる](https://qiita.com/kazama1209/items/7e16b2701cf9e27b1ca9)

本記事は↑の続きを想定しつつ書いていくつもりです。もしまだ読んでいない場合は目を通しておいてください。

Tipsにも書いてある通り、Multipass APIによるSSOを実運用する場合、Shopify ⇄ SSO基盤におけるデータの整合性を担保する必要があります。

特にメールアドレスはユニーク識別子とされているため、常に一意のものでなければなりません。もし仮に両者の整合性が取れなくなってしまうと、全く別のユーザーとしてログインしてしまう事になります。

そこで、たとえばSSO基盤側で登録情報を変更した場合などは、同時にShopify側の情報も変更するような仕組みを作っておかなければならないというわけですね。

[https://shopify.dev/docs/admin-api/rest/reference/customers/customer](https://shopify.dev/docs/admin-api/rest/reference/customers/customer)

Shopifyが提供するCustomer APIを使えばその要件が満たせるので、今回はそちらを試してみようと思います。

## 下準備

まず、Shopify APIを使用するための各種キーを発行しなければなりません。

![スクリーンショット 2021-04-12 18.27.46_censored (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/0da46350-03f8-720d-04b6-4c5d7f98088f.jpeg)

Shopify管理画面から「アプリ管理」→「プライベートアプリを管理する」へと進んでください。

![スクリーンショット 2021-04-12 18.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/49cd8cb4-5417-f5e4-5c86-f346dd6c8fbc.png)

右上の「新しいプライベートアプリを作成する」をクリック。

![スクリーンショット 2021-04-12 18.37.29_censored.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/ddf7c8a2-fd4a-14a6-db53-8f2c73b07d6c.jpeg)

- プライベートアプリ名
  - わかりやすい名前でOK
- 緊急連絡用開発者メール
  - 連絡のつきやすいメールアドレス
- Admin API権限
  - 顧客管理（読み取りおよび書き込み）
- Webhook APIのバージョン
  - とりあえず最新のものでOK

それぞれ必要な情報を記入し、プライベートアプリを作成してください。

![スクリーンショット 2021-04-12 18.41.15_censored.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/760f6faa-cbcf-2a7e-4c6b-55e219869299.jpeg)

上手くいくとこんな感じで

- APIキー
- パスワード

が発行されるので、メモなどに控えておきましょう。（後ほど使用します。）

## 実装

では、コードを書いていきます。

[https://github.com/kazama1209/shopify-multipass-api-on-rails](https://github.com/kazama1209/shopify-multipass-api-on-rails)

↑の続きとなっているので、手元にコードが無い場合はgit cloneなどしておいてください。

なお、今回Shopify Customer APIを叩くタイミングとして想定しているのは

- メールアドレス変更時
- ユーザー退会時

の2つです。

SSO基盤側でのメールアドレス変更時にShopify側のメールアドレスも変更しておかないと、次回ログインする際に別人として認識されてしまいますし、ユーザー退会時も何かしらの形でShopify側のメールアドレスを書き換えておかないと、もし後に同じメールアドレスを用いて再度SSO基盤側でユーザーを作成した際、Multipassログインができなくなってしまうからです。（Shopifyにおいて同一メールアドレスは複数存在し得ないため）

したがって、その辺のアクション実行時にAPI処理を挟んでいきます。

### gemをインストール

Shopify公式からAPI用のgemがリリースされているので、そちらをインストールしましょう。

```ruby:./Gemfile
gem 'shopify_api'
```

```
$ docker-compose build
```

### ライブラリを作成

```
$ touch lib/shopify_customer.rb
```

```ruby:./lib/shopify_customer.rb
class ShopifyCustomer
  # 初期設定
  def initialize
    shop_url = "https://<APIキー>:<パスワード>@<ストアのドメイン>"

    ShopifyAPI::Base.site = shop_url
    ShopifyAPI::Base.api_version = "2021-04"
    ShopifyAPI::Shop.current
  end

  # SSO基盤側でユーザー情報の変更（メールアドレスなど）を行った際、Shopify側の顧客情報を変更する。
  # 引数はキーワード引数形式で渡す（email: hoge@example.com, address: hogefugapiyo）。
  def update(multipass_identifier, **args)
    # Multipassログイン時に渡している「multipass_identifer」をもとに顧客情報を取得。
    customer = ShopifyAPI::Customer.search(multipass_identifier: multipass_identifier)[0]
    return false if customer.nil?

    customer.update_attributes(args)

    true
  rescue => e
    return false, e
  end
end
```

使えるメソッドなどについては公式ドキュメントを参照。
[https://github.com/Shopify/shopify_api/blob/master/lib/shopify_api/resources/customer.rb](https://github.com/Shopify/shopify_api/blob/master/lib/shopify_api/resources/customer.rb)


### メールアドレス変更時のAPI処理

```ruby:./app/controllers/users/registrations_controller.rb
  # PUT /resource
  def update
    super

    ShopifyCustomer.new.update(resource.id, email: resource.email)
  end
```

「Devise::RegistrationsController」を継承した「Users::RegistrationsController」内のupdateメソッドのコメントアウトを外し、オーバーライドします。

![スクリーンショット 2021-04-12 19.54.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/62b9b8e6-6dd4-06cf-6511-9982ff1691ca.png)

[http://localhost:3000/users/edit](http://localhost:3000/users/edit) にアクセスすると登録情報を変更できる画面に飛ぶので、試しに適当にメールアドレスを変更してみてください。

![スクリーンショット 2021-04-12 19.56.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/afb2a156-b4c9-d4d6-6a42-ca0fc7025848.png)

Shopify管理画面を見るとAPI経由で同時にメールアドレスが変更されているのを確認できるはず。

### ユーザー退会時のAPI処理

```ruby:./app/controllers/users/registrations_controller.rb
  # DELETE /resource
  def destroy
    super

    ShopifyCustomer.new.update(resource.id,
      email: "retired_user_#{resource.id}@example.com",
      tags: "withdrawn" # 退会した事がわかるようにタグを付与
    )
  end
```

先ほどと同じ要領で「destroy」メソッドのコメントアウトを外してオーバーライド。

現状、Multipassログインによって作成されたShopifyのユーザーはAPI経由で削除できないみたいなので（おそらく仕様？）、メールアドレスを適当な文字列で上書きする事で実質削除する「論理削除」的な処理で対応します。

![スクリーンショット 2021-04-12 20.05.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/2ce73337-1442-3831-abda-c52b6fd28d68.png)


[http://localhost:3000/users/edit](http://localhost:3000/users/edit) の最下部にある「Cancel my account」をクリックしましょう。

![スクリーンショット 2021-04-12 20.09.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/c8207b59-80cc-1996-53ce-883cfc872dce.png)

Shopify管理画面を見るとメールアドレスが「retired_user_{SSO基盤側のユーザーID}@example.com」で上書きされ、退会した事が一目でわかる「withdrawn」タグが付与されているのを確認できます。

## あとがき

以上、Shopify Customer APIを使って外部から顧客情報を操作してみました。実運用においてはもっと詳細なエラーハンドリングなどを行う必要があるでしょうが、ひとまず最低限の構成にはなっていると思います。

Shopify Multipass APIを用いたSSOは非常に手軽で便利なのですが、Shopify ⇄ SSO基盤間のデータの整合性を保つための工夫をしないと後々不具合が生じかねないため、上手くやりくりしたいところです。

もちろん、Shopifyでは顧客情報以外にも色々なリソースを操作できるので、公式ドキュメントを参考に色々試してみると良いかもしれません。

今回作成したアプリのソースコード:: [https://github.com/kazama1209/shopify-customer-api-on-rails](https://github.com/kazama1209/shopify-customer-api-on-rails)