shopify_api 4.9.0 → 9.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (281) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +36 -0
  4. data/.github/probots.yml +2 -0
  5. data/.github/workflows/build.yml +41 -0
  6. data/.gitignore +5 -1
  7. data/.rubocop.yml +28 -0
  8. data/.rubocop_todo.yml +75 -0
  9. data/CHANGELOG.md +491 -0
  10. data/CONTRIBUTING.md +1 -1
  11. data/Gemfile +6 -2
  12. data/Gemfile.lock +151 -0
  13. data/Gemfile_ar41 +5 -0
  14. data/Gemfile_ar50 +5 -0
  15. data/Gemfile_ar51 +5 -0
  16. data/Gemfile_ar_master +0 -1
  17. data/README.md +492 -100
  18. data/RELEASING +10 -9
  19. data/Rakefile +21 -5
  20. data/SECURITY.md +59 -0
  21. data/docker-compose.yml +13 -0
  22. data/docs/_config.yml +1 -0
  23. data/docs/_includes/footer.html +28 -0
  24. data/docs/_includes/head.html +28 -0
  25. data/docs/_layouts/index.html +57 -0
  26. data/docs/graphql.md +241 -0
  27. data/docs/index.md +639 -0
  28. data/lib/active_resource/connection_ext.rb +1 -0
  29. data/lib/active_resource/detailed_log_subscriber.rb +43 -7
  30. data/lib/active_resource/json_errors.rb +8 -2
  31. data/lib/shopify_api.rb +16 -6
  32. data/lib/shopify_api/api_access.rb +57 -0
  33. data/lib/shopify_api/api_version.rb +206 -0
  34. data/lib/shopify_api/connection.rb +7 -4
  35. data/lib/shopify_api/countable.rb +3 -2
  36. data/lib/shopify_api/disable_prefix_check.rb +31 -0
  37. data/lib/shopify_api/events.rb +2 -1
  38. data/lib/shopify_api/graphql.rb +103 -0
  39. data/lib/shopify_api/graphql/http_client.rb +22 -0
  40. data/lib/shopify_api/graphql/railtie.rb +17 -0
  41. data/lib/shopify_api/graphql/task.rake +100 -0
  42. data/lib/shopify_api/limits.rb +9 -9
  43. data/lib/shopify_api/message_enricher.rb +25 -0
  44. data/lib/shopify_api/meta.rb +14 -0
  45. data/lib/shopify_api/metafields.rb +5 -4
  46. data/lib/shopify_api/paginated_collection.rb +69 -0
  47. data/lib/shopify_api/pagination_link_headers.rb +34 -0
  48. data/lib/shopify_api/resources.rb +3 -1
  49. data/lib/shopify_api/resources/abandoned_checkout.rb +7 -0
  50. data/lib/shopify_api/resources/access_scope.rb +10 -0
  51. data/lib/shopify_api/resources/access_token.rb +1 -0
  52. data/lib/shopify_api/resources/address.rb +1 -0
  53. data/lib/shopify_api/resources/announcement.rb +2 -1
  54. data/lib/shopify_api/resources/api_permission.rb +9 -0
  55. data/lib/shopify_api/resources/application_charge.rb +1 -0
  56. data/lib/shopify_api/resources/application_credit.rb +1 -0
  57. data/lib/shopify_api/resources/array_base.rb +13 -0
  58. data/lib/shopify_api/resources/article.rb +3 -2
  59. data/lib/shopify_api/resources/asset.rb +28 -23
  60. data/lib/shopify_api/resources/assigned_fulfillment_order.rb +16 -0
  61. data/lib/shopify_api/resources/base.rb +101 -24
  62. data/lib/shopify_api/resources/billing_address.rb +2 -1
  63. data/lib/shopify_api/resources/blog.rb +2 -1
  64. data/lib/shopify_api/resources/carrier_service.rb +1 -0
  65. data/lib/shopify_api/resources/cart.rb +2 -1
  66. data/lib/shopify_api/resources/checkout.rb +27 -1
  67. data/lib/shopify_api/resources/collect.rb +2 -0
  68. data/lib/shopify_api/resources/collection.rb +14 -0
  69. data/lib/shopify_api/resources/collection_listing.rb +11 -1
  70. data/lib/shopify_api/resources/collection_publication.rb +10 -0
  71. data/lib/shopify_api/resources/comment.rb +20 -5
  72. data/lib/shopify_api/resources/country.rb +1 -0
  73. data/lib/shopify_api/resources/currency.rb +6 -0
  74. data/lib/shopify_api/resources/custom_collection.rb +7 -6
  75. data/lib/shopify_api/resources/customer.rb +2 -1
  76. data/lib/shopify_api/resources/customer_group.rb +1 -0
  77. data/lib/shopify_api/resources/{customer_invite_message.rb → customer_invite.rb} +1 -0
  78. data/lib/shopify_api/resources/customer_saved_search.rb +4 -1
  79. data/lib/shopify_api/resources/discount_code.rb +1 -0
  80. data/lib/shopify_api/resources/discount_code_batch.rb +34 -0
  81. data/lib/shopify_api/resources/draft_order.rb +1 -0
  82. data/lib/shopify_api/resources/draft_order_invoice.rb +1 -0
  83. data/lib/shopify_api/resources/event.rb +2 -0
  84. data/lib/shopify_api/resources/fulfillment.rb +46 -3
  85. data/lib/shopify_api/resources/fulfillment_event.rb +2 -1
  86. data/lib/shopify_api/resources/fulfillment_order.rb +151 -0
  87. data/lib/shopify_api/resources/fulfillment_order_locations_for_move.rb +5 -0
  88. data/lib/shopify_api/resources/fulfillment_request.rb +1 -0
  89. data/lib/shopify_api/resources/fulfillment_service.rb +1 -0
  90. data/lib/shopify_api/resources/fulfillment_v2.rb +21 -0
  91. data/lib/shopify_api/resources/gift_card.rb +1 -0
  92. data/lib/shopify_api/resources/image.rb +4 -3
  93. data/lib/shopify_api/resources/inventory_item.rb +6 -0
  94. data/lib/shopify_api/resources/inventory_level.rb +54 -0
  95. data/lib/shopify_api/resources/line_item.rb +10 -1
  96. data/lib/shopify_api/resources/location.rb +4 -0
  97. data/lib/shopify_api/resources/marketing_event.rb +3 -0
  98. data/lib/shopify_api/resources/metafield.rb +2 -0
  99. data/lib/shopify_api/resources/note_attribute.rb +1 -0
  100. data/lib/shopify_api/resources/option.rb +1 -0
  101. data/lib/shopify_api/resources/order.rb +25 -5
  102. data/lib/shopify_api/resources/order_risk.rb +1 -0
  103. data/lib/shopify_api/resources/page.rb +1 -0
  104. data/lib/shopify_api/resources/payment.rb +7 -0
  105. data/lib/shopify_api/resources/payment_details.rb +1 -0
  106. data/lib/shopify_api/resources/ping.rb +3 -0
  107. data/lib/shopify_api/resources/policy.rb +1 -0
  108. data/lib/shopify_api/resources/price_rule.rb +1 -1
  109. data/lib/shopify_api/resources/product.rb +33 -7
  110. data/lib/shopify_api/resources/product_listing.rb +9 -1
  111. data/lib/shopify_api/resources/product_publication.rb +10 -0
  112. data/lib/shopify_api/resources/province.rb +1 -0
  113. data/lib/shopify_api/resources/publication.rb +5 -0
  114. data/lib/shopify_api/resources/receipt.rb +1 -0
  115. data/lib/shopify_api/resources/recurring_application_charge.rb +4 -1
  116. data/lib/shopify_api/resources/redirect.rb +1 -0
  117. data/lib/shopify_api/resources/refund.rb +6 -4
  118. data/lib/shopify_api/resources/report.rb +1 -0
  119. data/lib/shopify_api/resources/resource_feedback.rb +1 -1
  120. data/lib/shopify_api/resources/rule.rb +1 -0
  121. data/lib/shopify_api/resources/script_tag.rb +1 -0
  122. data/lib/shopify_api/resources/shipping_address.rb +1 -0
  123. data/lib/shopify_api/resources/shipping_line.rb +2 -1
  124. data/lib/shopify_api/resources/shipping_rate.rb +7 -0
  125. data/lib/shopify_api/resources/shipping_zone.rb +1 -0
  126. data/lib/shopify_api/resources/shop.rb +10 -7
  127. data/lib/shopify_api/resources/smart_collection.rb +3 -3
  128. data/lib/shopify_api/resources/storefront_access_token.rb +1 -0
  129. data/lib/shopify_api/resources/tax_line.rb +1 -0
  130. data/lib/shopify_api/resources/tax_service.rb +1 -0
  131. data/lib/shopify_api/resources/tender_transaction.rb +6 -0
  132. data/lib/shopify_api/resources/theme.rb +1 -0
  133. data/lib/shopify_api/resources/transaction.rb +1 -0
  134. data/lib/shopify_api/resources/usage_charge.rb +1 -0
  135. data/lib/shopify_api/resources/user.rb +1 -0
  136. data/lib/shopify_api/resources/variant.rb +35 -0
  137. data/lib/shopify_api/resources/webhook.rb +1 -0
  138. data/lib/shopify_api/session.rb +109 -45
  139. data/lib/shopify_api/version.rb +2 -1
  140. data/lib/verify_docs.rb +8 -0
  141. data/service.yml +8 -0
  142. data/shopify_api.gemspec +19 -8
  143. data/test/abandoned_checkouts_test.rb +29 -0
  144. data/test/access_scope_test.rb +23 -0
  145. data/test/access_token_test.rb +6 -5
  146. data/test/active_resource/json_errors_test.rb +6 -6
  147. data/test/api_access_test.rb +153 -0
  148. data/test/api_permission_test.rb +9 -0
  149. data/test/api_version_test.rb +157 -0
  150. data/test/application_charge_test.rb +30 -27
  151. data/test/application_credit_test.rb +10 -9
  152. data/test/article_test.rb +34 -35
  153. data/test/asset_test.rb +14 -6
  154. data/test/assigned_fulfillment_order_test.rb +78 -0
  155. data/test/base_test.rb +147 -59
  156. data/test/blog_test.rb +4 -3
  157. data/test/carrier_service_test.rb +7 -6
  158. data/test/cart_test.rb +2 -1
  159. data/test/checkouts_test.rb +72 -4
  160. data/test/collect_test.rb +4 -3
  161. data/test/collection_listing_test.rb +56 -13
  162. data/test/collection_publication_test.rb +40 -0
  163. data/test/collection_test.rb +50 -0
  164. data/test/countable_test.rb +3 -2
  165. data/test/currency_test.rb +21 -0
  166. data/test/custom_collection_test.rb +4 -3
  167. data/test/customer_saved_search_test.rb +18 -8
  168. data/test/customer_test.rb +22 -14
  169. data/test/detailed_log_subscriber_test.rb +113 -19
  170. data/test/discount_code_batch_test.rb +41 -0
  171. data/test/discount_code_test.rb +22 -16
  172. data/test/draft_order_test.rb +68 -52
  173. data/test/fixtures/abandoned_checkout.json +184 -0
  174. data/test/fixtures/abandoned_checkouts.json +186 -0
  175. data/test/fixtures/access_scopes.json +10 -0
  176. data/test/fixtures/api_versions.json +38 -0
  177. data/test/fixtures/apis.json +42 -0
  178. data/test/fixtures/assigned_fulfillment_orders.json +80 -0
  179. data/test/fixtures/checkout.json +160 -0
  180. data/test/fixtures/checkouts.json +25 -49
  181. data/test/fixtures/collection.json +17 -0
  182. data/test/fixtures/collection_listing_product_ids2.json +1 -0
  183. data/test/fixtures/collection_products.json +47 -0
  184. data/test/fixtures/collection_publication.json +11 -0
  185. data/test/fixtures/collection_publications.json +13 -0
  186. data/test/fixtures/currencies.json +25 -0
  187. data/test/fixtures/discount_code_batch.json +14 -0
  188. data/test/fixtures/discount_code_batch_discount_codes.json +21 -0
  189. data/test/fixtures/fulfillment_order.json +39 -0
  190. data/test/fixtures/fulfillment_order_locations_for_move.json +18 -0
  191. data/test/fixtures/fulfillment_orders.json +80 -0
  192. data/test/fixtures/fulfillments.json +53 -0
  193. data/test/fixtures/graphql/2019-10.json +1083 -0
  194. data/test/fixtures/graphql/dummy_schema.rb +16 -0
  195. data/test/fixtures/graphql/unstable.json +1083 -0
  196. data/test/fixtures/inventory_level.json +7 -0
  197. data/test/fixtures/inventory_levels.json +24 -0
  198. data/test/fixtures/order_with_properties.json +373 -0
  199. data/test/fixtures/payment.json +7 -0
  200. data/test/fixtures/payments.json +9 -0
  201. data/test/fixtures/ping/conversation.json +1 -0
  202. data/test/fixtures/ping/failed_delivery_confirmation.json +1 -0
  203. data/test/fixtures/ping/message.json +1 -0
  204. data/test/fixtures/ping/successful_delivery_confirmation.json +1 -0
  205. data/test/fixtures/product_listing_product_ids.json +1 -1
  206. data/test/fixtures/product_listing_product_ids2.json +1 -0
  207. data/test/fixtures/product_publication.json +11 -0
  208. data/test/fixtures/product_publications.json +13 -0
  209. data/test/fixtures/publications.json +9 -0
  210. data/test/fixtures/shipping_rates.json +12 -0
  211. data/test/fixtures/smart_collection_products.json +155 -0
  212. data/test/fixtures/tender_transactions.json +52 -0
  213. data/test/fulfillment_event_test.rb +31 -26
  214. data/test/fulfillment_order_test.rb +530 -0
  215. data/test/fulfillment_order_test_helper.rb +8 -0
  216. data/test/fulfillment_request_test.rb +10 -8
  217. data/test/fulfillment_service_test.rb +13 -12
  218. data/test/fulfillment_test.rb +198 -20
  219. data/test/fulfillment_v2_test.rb +66 -0
  220. data/test/gift_card_test.rb +6 -4
  221. data/test/graphql/http_client_test.rb +26 -0
  222. data/test/graphql_test.rb +190 -0
  223. data/test/image_test.rb +19 -17
  224. data/test/inventory_level_test.rb +68 -0
  225. data/test/lib/webmock_extensions/last_request.rb +16 -0
  226. data/test/limits_test.rb +4 -3
  227. data/test/location_test.rb +15 -0
  228. data/test/marketing_event_test.rb +21 -21
  229. data/test/message_enricher_test.rb +45 -0
  230. data/test/meta_test.rb +47 -0
  231. data/test/metafield_test.rb +30 -20
  232. data/test/order_risk_test.rb +17 -16
  233. data/test/order_test.rb +110 -17
  234. data/test/pagination_test.rb +290 -0
  235. data/test/payment_test.rb +19 -0
  236. data/test/policy_test.rb +6 -5
  237. data/test/price_rule_test.rb +20 -15
  238. data/test/product_listing_test.rb +72 -15
  239. data/test/product_publication_test.rb +40 -0
  240. data/test/product_test.rb +80 -19
  241. data/test/publication_test.rb +12 -0
  242. data/test/recurring_application_charge_test.rb +105 -50
  243. data/test/redirect_test.rb +4 -3
  244. data/test/refund_test.rb +22 -17
  245. data/test/report_test.rb +12 -10
  246. data/test/resource_feedback_test.rb +14 -13
  247. data/test/script_tag_test.rb +10 -9
  248. data/test/session_test.rb +497 -111
  249. data/test/shipping_rate_test.rb +17 -0
  250. data/test/shipping_zone_test.rb +4 -3
  251. data/test/shop_test.rb +47 -33
  252. data/test/smart_collection_test.rb +5 -4
  253. data/test/storefront_access_token_test.rb +13 -15
  254. data/test/tax_service_test.rb +7 -3
  255. data/test/tender_transaction_test.rb +18 -0
  256. data/test/test_helper.rb +98 -67
  257. data/test/transaction_test.rb +4 -3
  258. data/test/usage_charge_test.rb +12 -8
  259. data/test/user_test.rb +4 -3
  260. data/test/variant_test.rb +50 -20
  261. data/test/webhook_test.rb +10 -7
  262. metadata +196 -37
  263. data/.travis.yml +0 -36
  264. data/CHANGELOG +0 -292
  265. data/Gemfile_ar30 +0 -6
  266. data/Gemfile_ar31 +0 -6
  267. data/Gemfile_ar32 +0 -6
  268. data/Gemfile_ar40 +0 -6
  269. data/bin/shopify +0 -3
  270. data/lib/active_resource/base_ext.rb +0 -21
  271. data/lib/active_resource/disable_prefix_check.rb +0 -36
  272. data/lib/active_resource/to_query.rb +0 -10
  273. data/lib/shopify_api/json_format.rb +0 -18
  274. data/lib/shopify_api/resources/discount.rb +0 -11
  275. data/lib/shopify_api/resources/o_auth.rb +0 -9
  276. data/test/discount_test.rb +0 -52
  277. data/test/fixtures/discount.json +0 -17
  278. data/test/fixtures/discount_disabled.json +0 -17
  279. data/test/fixtures/discounts.json +0 -34
  280. data/test/fixtures/o_auth_revoke.json +0 -5
  281. data/test/o_auth_test.rb +0 -8
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyAPI
3
+ module DisablePrefixCheck
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def check_prefix_options(options)
8
+ end
9
+
10
+ # `flexible = true` is hack to allow multiple things through the same AR class
11
+ def conditional_prefix(resource, flexible = false)
12
+ resource_id = "#{resource}_id".to_sym
13
+ resource_type = flexible ? ":#{resource}" : resource.to_s.pluralize
14
+
15
+ init_prefix_explicit(resource_type, resource_id)
16
+
17
+ define_singleton_method(:resource_prefix) do |options = {}|
18
+ resource_type = options[resource] if flexible
19
+
20
+ options[resource_id].nil? ? '' : "#{resource_type}/#{options[resource_id]}/"
21
+ end
22
+
23
+ define_singleton_method(:instantiate_record) do |record, prefix_options = {}|
24
+ new(record, true).tap do |resource_instance|
25
+ resource_instance.prefix_options = prefix_options unless prefix_options.blank?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module ShopifyAPI
2
3
  module Events
3
4
  def events
4
- Event.find(:all, :params => {:resource => self.class.collection_name, :resource_id => id})
5
+ Event.find(:all, params: { resource: self.class.collection_name, resource_id: id })
5
6
  end
6
7
  end
7
8
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+ require 'graphql/client'
3
+ require 'shopify_api/graphql/http_client'
4
+
5
+ module ShopifyAPI
6
+ module GraphQL
7
+ DEFAULT_SCHEMA_LOCATION_PATH = Pathname('shopify_graphql_schemas')
8
+ DEFAULT_EXECUTION_ADAPTER = HTTPClient
9
+ DEFAULT_GRAPHQL_CLIENT = ::GraphQL::Client
10
+
11
+ InvalidSchema = Class.new(StandardError)
12
+ InvalidClient = Class.new(StandardError)
13
+
14
+ class << self
15
+ delegate :parse, :query, to: :client
16
+
17
+ def client(api_version = ShopifyAPI::Base.api_version.handle)
18
+ initialize_client_cache
19
+ cached_client = @_client_cache[api_version]
20
+
21
+ if cached_client
22
+ cached_client
23
+ else
24
+ schema_file = schema_location.join("#{api_version}.json")
25
+
26
+ if !schema_file.exist?
27
+ raise InvalidClient, <<~MSG
28
+ Client for API version #{api_version} does not exist because no schema file exists at `#{schema_file}`.
29
+
30
+ To dump the schema file, use the `rake shopify_api:graphql:dump` task.
31
+ MSG
32
+ else
33
+ puts(
34
+ '[WARNING] Client was not pre-initialized. Ensure `ShopifyAPI::GraphQL.initialize_clients` ' \
35
+ 'is called during app initialization.'
36
+ )
37
+ initialize_clients
38
+ @_client_cache[api_version]
39
+ end
40
+ end
41
+ end
42
+
43
+ def clear_clients
44
+ @_client_cache = {}
45
+ end
46
+
47
+ def initialize_clients(raise_on_invalid_schema: true)
48
+ initialize_client_cache
49
+
50
+ Dir.glob(schema_location.join("*.json")).each do |schema_file|
51
+ schema_file = Pathname(schema_file)
52
+ matches = schema_file.basename.to_s.match(/^#{ShopifyAPI::ApiVersion::HANDLE_FORMAT}\.json$/)
53
+
54
+ if matches
55
+ api_version = ShopifyAPI::ApiVersion.new(handle: matches[1])
56
+ elsif raise_on_invalid_schema
57
+ raise InvalidSchema,
58
+ "Invalid schema file name `#{schema_file}`. Does not match format of: `<version>.json`."
59
+ else
60
+ next
61
+ end
62
+
63
+ schema = graphql_client.load_schema(schema_file.to_s)
64
+ client = graphql_client.new(schema: schema, execute: execution_adapter.new(api_version)).tap do |c|
65
+ c.allow_dynamic_queries = true
66
+ end
67
+
68
+ @_client_cache[api_version.handle] = client
69
+ end
70
+ end
71
+
72
+ def schema_location
73
+ @schema_location || DEFAULT_SCHEMA_LOCATION_PATH
74
+ end
75
+
76
+ def schema_location=(path)
77
+ @schema_location = Pathname(path)
78
+ end
79
+
80
+ def execution_adapter
81
+ @execution_adapter || DEFAULT_EXECUTION_ADAPTER
82
+ end
83
+
84
+ def execution_adapter=(executor)
85
+ @execution_adapter = executor
86
+ end
87
+
88
+ def graphql_client
89
+ @graphql_client || DEFAULT_GRAPHQL_CLIENT
90
+ end
91
+
92
+ def graphql_client=(client)
93
+ @graphql_client = client
94
+ end
95
+
96
+ private
97
+
98
+ def initialize_client_cache
99
+ @_client_cache ||= {}
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require 'graphql/client/http'
3
+
4
+ module ShopifyAPI
5
+ module GraphQL
6
+ class HTTPClient < ::GraphQL::Client::HTTP
7
+ def initialize(api_version)
8
+ @api_version = api_version
9
+ end
10
+
11
+ def headers(_context)
12
+ ShopifyAPI::Base.headers
13
+ end
14
+
15
+ def uri
16
+ ShopifyAPI::Base.site.dup.tap do |uri|
17
+ uri.path = @api_version.construct_graphql_path
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/railtie'
3
+
4
+ module ShopifyAPI
5
+ module GraphQL
6
+ class Railtie < Rails::Railtie
7
+ initializer 'shopify_api.initialize_graphql_clients' do |app|
8
+ ShopifyAPI::GraphQL.schema_location = app.root.join('db', ShopifyAPI::GraphQL.schema_location)
9
+ ShopifyAPI::GraphQL.initialize_clients
10
+ end
11
+
12
+ rake_tasks do
13
+ load 'shopify_api/graphql/task.rake'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+ require 'fileutils'
3
+
4
+ namespace :shopify_api do
5
+ namespace :graphql do
6
+ desc 'Dumps a local JSON schema file of the Shopify Admin API'
7
+ task :dump do
8
+ usage = <<~USAGE
9
+
10
+ Usage: rake shopify_api:graphql:dump [<args>]
11
+
12
+ Dumps a local JSON schema file of the Shopify Admin API. The schema is specific to an
13
+ API version and authentication is required (either OAuth or private app).
14
+
15
+ Dump the schema file for the 2020-01 API version using private app authentication:
16
+ $ rake shopify_api:graphql:dump SHOP_URL="https://API_KEY:PASSWORD@SHOP_NAME.myshopify.com" API_VERSION=2020-01
17
+
18
+ Dump the schema file for the unstable API version using an OAuth access token:
19
+ $ rake shopify_api:graphql:dump SHOP_DOMAIN=SHOP_NAME.myshopify.com ACCESS_TOKEN=abc API_VERSION=unstable
20
+
21
+ See https://github.com/Shopify/shopify_api#getting-started for more
22
+ details on getting started with authenticated API calls.
23
+
24
+ Arguments:
25
+ ACCESS_TOKEN OAuth access token (shop specific)
26
+ API_VERSION API version handle [example: 2020-01]
27
+ SHOP_DOMAIN Shop domain (without path) [example: SHOP_NAME.myshopify.com]
28
+ SHOP_URL Shop URL for private apps [example: https://API_KEY:PASSWORD@SHOP_NAME.myshopify.com]
29
+ USAGE
30
+
31
+ access_token = ENV['ACCESS_TOKEN'] || ENV['access_token']
32
+ api_version = ENV['API_VERSION'] || ENV['api_version']
33
+ shop_url = ENV['SHOP_URL'] || ENV['shop_url']
34
+ shop_domain = ENV['SHOP_DOMAIN'] || ENV['shop_domain']
35
+
36
+ unless access_token || api_version || shop_url || shop_domain
37
+ puts usage
38
+ exit(1)
39
+ end
40
+
41
+ unless shop_url || shop_domain
42
+ puts 'Error: either SHOP_DOMAIN or SHOP_URL is required for authentication'
43
+ puts usage
44
+ exit(1)
45
+ end
46
+
47
+ if shop_url && shop_domain
48
+ puts 'Error: SHOP_DOMAIN and SHOP_URL cannot be used together. Use one or the other for authentication.'
49
+ puts usage
50
+ exit(1)
51
+ end
52
+
53
+ if shop_domain && !access_token
54
+ puts 'Error: ACCESS_TOKEN required when SHOP_DOMAIN is used'
55
+ puts usage
56
+ exit(1)
57
+ end
58
+
59
+ unless api_version
60
+ puts 'Error: API_VERSION required. Example: 2020-01'
61
+ puts usage
62
+ exit(1)
63
+ end
64
+
65
+ Rake::Task['environment'].invoke if Rake::Task.task_defined?('environment')
66
+
67
+ ShopifyAPI::ApiVersion.fetch_known_versions
68
+ ShopifyAPI::ApiVersion.version_lookup_mode = :raise_on_unknown
69
+
70
+ shopify_session = ShopifyAPI::Session.new(domain: shop_domain, token: access_token, api_version: api_version)
71
+ ShopifyAPI::Base.activate_session(shopify_session)
72
+
73
+ if shop_url
74
+ ShopifyAPI::Base.site = shop_url
75
+ end
76
+
77
+ puts "Fetching schema for #{ShopifyAPI::Base.api_version.handle} API version..."
78
+
79
+ client = ShopifyAPI::GraphQL::HTTPClient.new(ShopifyAPI::Base.api_version)
80
+ document = GraphQL.parse('{ __schema { queryType { name } } }')
81
+ response = client.execute(document: document).to_h
82
+
83
+ unless response['data'].present?
84
+ puts "Error: failed to query the API."
85
+ puts "Response: #{response}"
86
+ puts 'Ensure your SHOP_DOMAIN or SHOP_URL are valid and you have valid authentication credentials.'
87
+ puts usage
88
+ exit(1)
89
+ end
90
+
91
+ schema_location = ShopifyAPI::GraphQL.schema_location
92
+ FileUtils.mkdir_p(schema_location) unless Dir.exist?(schema_location)
93
+
94
+ schema_file = schema_location.join("#{api_version}.json")
95
+ GraphQL::Client.dump_schema(client, schema_file.to_s)
96
+
97
+ puts "Wrote file #{schema_file}"
98
+ end
99
+ end
100
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ShopifyAPI
2
3
  module Limits
3
4
  class LimitUnavailable < StandardError; end
@@ -7,14 +8,14 @@ module ShopifyAPI
7
8
  end
8
9
 
9
10
  module ClassMethods
10
-
11
- # Takes form num_requests_executed/max_requests
12
- # Eg: 101/3000
11
+ # Takes form <call count>/<bucket size>
12
+ # See https://help.shopify.com/en/api/getting-started/api-call-limit
13
+ # Eg: 2/40
13
14
  CREDIT_LIMIT_HEADER_PARAM = {
14
- :shop => 'http_x_shopify_shop_api_call_limit'
15
+ shop: 'X-Shopify-Shop-Api-Call-Limit',
15
16
  }
16
17
 
17
- ##
18
+ ##
18
19
  # How many more API calls can I make?
19
20
  # @return {Integer}
20
21
  #
@@ -38,9 +39,8 @@ module ShopifyAPI
38
39
  # @param {Symbol} scope [:shop]
39
40
  # @return {Integer}
40
41
  #
41
- def credit_limit(scope=:shop)
42
- @api_credit_limit ||= {}
43
- @api_credit_limit[scope] ||= api_credit_limit_param(scope).pop.to_i - 1
42
+ def credit_limit(scope = :shop)
43
+ api_credit_limit_param(scope).pop.to_i - 1
44
44
  end
45
45
  alias_method :call_limit, :credit_limit
46
46
 
@@ -49,7 +49,7 @@ module ShopifyAPI
49
49
  # @param {Symbol} scope [:shop]
50
50
  # @return {Integer}
51
51
  #
52
- def credit_used(scope=:shop)
52
+ def credit_used(scope = :shop)
53
53
  api_credit_limit_param(scope).shift.to_i
54
54
  end
55
55
  alias_method :call_count, :credit_used
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyAPI
3
+ class MessageEnricher < SimpleDelegator
4
+ def message
5
+ return super unless (400...500).include?(code.to_i)
6
+
7
+ @_cached_message ||= begin
8
+ detailed_error =
9
+ begin
10
+ parsed_body = JSON.parse(body)
11
+
12
+ if parsed_body['error']
13
+ parsed_body['error'].to_s
14
+ elsif parsed_body['errors']
15
+ Array(parsed_body['errors']).join('; ')
16
+ end
17
+ rescue JSON::ParserError
18
+ nil
19
+ end
20
+
21
+ detailed_error.present? ? "#{super} (#{detailed_error})" : super
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+
2
+ # frozen_string_literal: true
3
+ module ShopifyAPI
4
+ class Meta < ActiveResource::Base
5
+ self.site = "https://app.shopify.com/services/"
6
+ self.element_name = 'api'
7
+ self.primary_key = :handle
8
+ self.timeout = 5
9
+
10
+ def self.admin_versions
11
+ all.find { |api| api.handle = :admin }.versions
12
+ end
13
+ end
14
+ end
@@ -1,17 +1,18 @@
1
+ # frozen_string_literal: true
1
2
  module ShopifyAPI
2
3
  module Metafields
3
4
  def metafields(**options)
4
- options.merge! resource: self.class.collection_name, resource_id: id
5
+ options.merge!(resource: self.class.collection_name, resource_id: id)
5
6
 
6
- Metafield.find :all, params: options
7
+ Metafield.find(:all, params: options)
7
8
  end
8
9
 
9
10
  def add_metafield(metafield)
10
11
  raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
11
12
 
12
13
  metafield.prefix_options = {
13
- :resource => self.class.collection_name,
14
- :resource_id => id
14
+ resource: self.class.collection_name,
15
+ resource_id: id,
15
16
  }
16
17
  metafield.save
17
18
  metafield
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyAPI
4
+ class PaginatedCollection < ActiveResource::Collection
5
+ module CollectionPagination
6
+ def initialize(args)
7
+ @next_url = pagination_link_headers.next_link&.url&.to_s
8
+ @previous_url = pagination_link_headers.previous_link&.url&.to_s
9
+ super(args)
10
+ end
11
+
12
+ def next_page?
13
+ ensure_available
14
+ @next_url.present?
15
+ end
16
+
17
+ def previous_page?
18
+ ensure_available
19
+ @previous_url.present?
20
+ end
21
+
22
+ def fetch_next_page
23
+ fetch_page(@next_url)
24
+ end
25
+
26
+ def fetch_previous_page
27
+ fetch_page(@previous_url)
28
+ end
29
+
30
+ def next_page_info
31
+ extract_page_info(@next_url)
32
+ end
33
+
34
+ def previous_page_info
35
+ extract_page_info(@previous_url)
36
+ end
37
+
38
+ private
39
+
40
+ AVAILABLE_IN_VERSION = ShopifyAPI::ApiVersion.find_version('2019-10')
41
+ AVAILABLE_IN_VERSION_EARLY = ShopifyAPI::ApiVersion.find_version('2019-07')
42
+
43
+ def fetch_page(url)
44
+ ensure_available
45
+ return [] unless url.present?
46
+
47
+ resource_class.all(from: url)
48
+ end
49
+
50
+ def pagination_link_headers
51
+ @pagination_link_headers ||= ShopifyAPI::PaginationLinkHeaders.new(
52
+ ShopifyAPI::Base.connection.response["Link"]
53
+ )
54
+ end
55
+
56
+ def ensure_available
57
+ return if ShopifyAPI::Base.api_version >= AVAILABLE_IN_VERSION
58
+ return if ShopifyAPI::Base.api_version >= AVAILABLE_IN_VERSION_EARLY && resource_class.early_july_pagination?
59
+ raise NotImplementedError
60
+ end
61
+
62
+ def extract_page_info(url)
63
+ CGI.escape(Rack::Utils.parse_query(URI(url).query)['page_info']) if url.present?
64
+ end
65
+ end
66
+
67
+ include CollectionPagination
68
+ end
69
+ end