💥

Shopify/Ruby: プライベートアプリのAPI設定で BAD_REQUEST エラーが出る場合の対処法

2023/03/29に公開

環境

  • Ruby 2.6.9
  • gem shopify_api 10.1.0

背景

Fulfillment APIが利用できなくなるため、Shopifyプライベートアプリの gem shopify_api をv9からv10にアップグレードにしないといけませんでした。

エラー

ビルトインのRESTリソース(Shop.all など)を利用した場合、Product.updateInventoryItem.find などの一部のAPIエンドポイントで以下のエラーが発生しました。

ShopifyAPI::Errors::HttpResponseError: {"message"=>"Bad Request", "extensions"=>{"code"=>"BAD_REQUEST"}}

また同エラーでGraphQLも同様に一部利用できませんでした。

原因

gemのREADMEに基づき、設定ファイルは以下のように書いていました。

scope = %w[
  read_content
  read_customers
  write_orders
  write_products
  write_inventory
  write_fulfillments
  write_assigned_fulfillment_orders
  write_merchant_managed_fulfillment_orders
  write_third_party_fulfillment_orders
  write_custom_fulfillment_services
].join(',')

ShopifyAPI::Context.setup(
  api_key: Rails.application.credentials.shopify[:api_key],
  api_secret_key: Rails.application.credentials.shopify[:api_secret_key],
  host: "https://application-host-name.com",
  scope: scope,
  session_storage: ShopifyAPI::Auth::FileSessionStorage.new,
  is_embedded: false,
  api_version: "2022-04",
  is_private: true,
)
session = ShopifyAPI::Auth::Session.new(
  shop: 'application-host-name.com',
  access_token: Rails.application.credentials.shopify[:api_access_token]
)
p = ShopifyAPI::Product.find(session: session, id: 123456789)
p.title = "new title"
p.update!
# ShopifyAPI::Errors::HttpResponseError: {"message"=>"Bad Request", "extensions"=>{"code"=>"BAD_REQUEST"}}

ダッシュボードで生成されたAPIアクセストークンのみ使ったプライベートアプリの設定方法がドキュメントでは明確じゃないのですが、どうやら問題は Auth::Sessionshop はカスタムドメイン(application-host-name.com)ではなく「myshopify.comドメイン」でないとダメだったみたいです。

解決策

同エラーに関連するIssueページ:https://github.com/Shopify/shopify-api-ruby/issues/91

スレッドのアドバイスに基づいて以下の変更を行い、ついにプライベートアプリが shopify_api v10で動作するようになりました🎉

ShopifyAPI::Context.setup(
  # These values are required but not actually used for private apps
  api_key: "DUMMY_VALUE",
  host_name: "DUMMY_VALUE",
  scope: "DUMMY_VALUE",

  private_shop: 'your.myshopify.com',
  api_secret_key: Rails.application.credentials.shopify[:api_access_token],

  session_storage: ShopifyAPI::Auth::FileSessionStorage.new,
  is_embedded: false,
  is_private: true,
  api_version: '2022-04',
)
  • private_shop: <your.myshopify.com>
  • api_secret_key: APIアクセストークン
  • api_key, host_name, scope は無視してOK
session = ShopifyAPI::Utils::SessionUtils.load_current_session
p = ShopifyAPI::Product.find(session: session, id: 123456789)
p.title = "new title"
p.update!
# T::Private::Types::Void::VOID

Discussion