1年間向き合ったShopifyアプリ開発の面倒なところを共通化した

CARTA TECH BLOG アドベントカレンダー 12月14日分の記事です。

サンプルコード書いてたらハマってしまって書くの遅れました。

はじめに

こんにちは、株式会社fluctでエンジニアをしてる ryokosuge (こすげ)です。 今はコマースまわりの開発を担当しております。 今年1年間、Shopifyに関連する開発をしていました。

www.shopify.com

特に頑張ったのがアプリ開発でして、英語のドキュメントを読みながら、時にはShopifyの日本サポートの人に質問したりと四苦八苦しながらも要望答えられるように作りました。

shopify.dev

Shopifyのアプリ開発自体はそこまで難しくありません。 というのもドキュメントに全て答えが乗っているので、API叩く順番や表示する内容などに気にすれば大抵のことが実現できるように環境を用意してくださっています。

ただAPIを叩いたり、Shop(マーチャント)管理画面にインストールして動かせるようになるまでにやらないといけないことが以下の2つです。

  1. 認証(Authentication)
  2. サブスクリプション(有料アプリのみ)

この2つ、毎回用意するのがとても面倒(理解すればそこまで難しくない)なので、今回の記事に合わせて(復習も兼ねて)テンプレートアプリみたいなものを作ってみました。 機能もできる限りわかりやすいようにPR分けて開発してみました。

github.com

Remixは個人的にすごい好きで今年作ったアプリでも採用してます。

あとは最近 提携した というのも個人的にはすごく嬉しい話題でした。

上記のリポジトリのコードを元に説明していきます。

記事について

この記事では認証とサブスクに絞って書きます。

他の点で知りたいところとかあったらどんな手段でもいいので連絡してください、追って記事でも書ければなと思います。

上記のリポジトリをcloneして make したら以下のスクショのところまで一気に使えます。

make実行時のログ

❯ make
npm i -g yarn@latest

changed 1 package, and audited 2 packages in 1s

found 0 vulnerabilities
yarn
yarn install v1.22.19
[1/4] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.22s.
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C web install
yarn
yarn install v1.22.19
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.37s.
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C web db
yarn prisma db push
yarn run v1.22.19
$ prisma db push
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./db/dev.db"

The database is already in sync with the Prisma schema.

✔ Generated Prisma Client (4.8.0 | library) to ./node_modules/@prisma/client in 79ms

✨  Done in 2.77s.
yarn shopify app dev
yarn run v1.22.19
$ shopify app dev
✔ Dependencies installed

To run this command, log in to Shopify Partners.
👉 Press any key to open the login page on your browser
✔ Logged in.

Looks like this is the first time you're running dev for this project.
Configure your preferences by answering a few questions.


Before you preview your work, it needs to be associated with an app.

✔ Create this project as a new app on Shopify? · No, connect it to an existing app
✔ Which existing app is this for? · sample-remix-app
✔ Which development store would you like to use to view your project? · sample-remix-app
✅ Success! The tunnel is running and you can now view your app.

Your app's URL currently is:
  https://0c8f-2400-4050-2a81-da00-487-2cc9-974e-d514.ngrok.io/

Your app's redirect URLs currently are:
  https://0c8f-2400-4050-2a81-da00-487-2cc9-974e-d514.ngrok.io/auth/callback
  https://0c8f-2400-4050-2a81-da00-487-2cc9-974e-d514.ngrok.io/auth/shopify/callback
  https://0c8f-2400-4050-2a81-da00-487-2cc9-974e-d514.ngrok.io/api/auth/callback

✔ Have Shopify automatically update your app's URL in order to create a preview experience? · Always by default
✔ URL updated


Shareable app URL

  https://0750-2400-4050-2a81-da00-487-2cc9-974e-d514.ngrok.io?shop=sample-remix-app.myshopify.com&host=c2FtcGxlLXJlbWl4LWFwcC5teXNob3BpZnkuY29tL2FkbWlu

2022-12-22 06:52:10 | frontend |
2022-12-22 06:52:10 | frontend | $ cross-env HOST="localhost" remix dev
2022-12-22 06:52:15 | frontend | Loading environment variables from .env
2022-12-22 06:52:16 | frontend | Remix App Server started at http://localhost:59120 (http://localhost:59120)

それでは詳しく書いていきます。

Shopifyアプリの認証について

shopify.dev

このドキュメントに全て書かれています。 今回作ったアプリは楽をして以下のライブラリを採用しました。

github.com

PRで言うと以下の部分になります。

github.com

注意する点として

  • Shopifyアプリの認証のドメインはshop毎に振られるユニークなドメイン
    • *.myshopify.com と言うやつ
    • アプリをインストールするShop毎なので動的に変える必要がある

https://github.com/ryokosuge/shopify-remix-app/blob/main/web/app/libs/auth/strategy/shopify.server.ts#L44-L58

  request: Request,
  sessionStorage: SessionStorage,
  options: AuthenticateOptions,
): Promise<User> {
  const shop = options.context?.shop as string;
  if (shop == null) {
    throw new Error("Not found shop domain.");
  }

  this.authorizationURL = `https://${shop}/admin/oauth/authorize`;
  this.tokenURL = `https://${shop}/admin/oauth/access_token`;
  this.myshopifyDomain = shop;
  return super.authenticate(request, sessionStorage, options);
}

なので上記のように認証処理をする前に authroizationURL(認証画面)tokenURL (accessToken発行) を書き換えてあげる必要があります。

あとはライブラリに任せるといい感じにcallbackでaccessTokenが取得できます。

accessTokenを取得したあとは永続化してください。

処理の流れはOAuthのまんまです。もし気になる場合は以下のドキュメントを読むといいと思います。

shopify.dev

またShopifyのアクセストークンを発行する際にアクセスモードというものがあります。

永続的に使用するのか、ユーザー毎に使うのかなどユースケースに合わせて用途が変わるので気になる方は以下のドキュメントも合わせて読んでください。

shopify.dev

サブスクリプション

もう一つ公開アプリを作成するときに考えないといけないのが課金になります。

せっかくアプリ作ったならお金欲しいですよね?

私はお金がとても欲しいので、しっかり調べて取りこぼしのない様に実装しました。

PRだと以下の内容になります。

github.com

コードを見れば分かるとおり、ShopifyのGraphQL Admin APIを叩きまくっています。

上記の認証後から始まる処理の流れは以下の様になっています。

課金完了後にcallbackで charge_idというものを受け取って永続化しています。サブスクリプションのIDになります。

これはあくまで月額課金の流れになっていまして、1度限りや都度課金に関してはまた別のフローになるかもしれません。(多分1度限りの課金も同じフローになると思います。)

都度課金に関してはまだ私が実装したことないので詳しくありません......。

以下がドキュメントになります。

shopify.dev

これで月額課金も問題なく実装できました。

終わりに

Shopifyアプリを開発する上で結構気にしないといけないことが他にもいくつかあります。

例えばWebhooksです。

Shopifyからのrequestに6秒以内にresponse返す必要がありちょっと長い処理をする際にはインフラ構成からしっかり考える必要があります。

今回作ったサンプルはアプリに特化していますが、弊社内ではAWS CDKを使ったインフラ構成管理なども共通化してすぐに本番環境まで構築できるようにしてあります。

ここら辺はまた別でいつか紹介できたら......。

ということでShopifyアプリに関する記事でした。最後まで読んでいただきありがとうございました。