shopify_graphql 1.2.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2665c3ed8b5b9d23122eea1f5b2aa732e498c121b84e8107d8a38fa72f283194
4
- data.tar.gz: 9c9419934d87bbbc83466062979645be6747567425c3ef00a544f106e77b086f
3
+ metadata.gz: fe9ea3cbb7c46d86fe1281d9658cc1de370db1b306b29aa331c1c8ac9ae94f0d
4
+ data.tar.gz: ab91936f744cd3c40ee1b81952426a839e26fb3fd8b9ca55defa5248c22ed812
5
5
  SHA512:
6
- metadata.gz: c5ea8982a3f9ab9886da4999e56f6de96b86393866b802ccda7d0b8203799dc3679dfb7ce1705b036bc67fa77e41315ab00e40804b728bd369933845c85ddc59
7
- data.tar.gz: 20e14ad87d2de46ce703ba1787dfe3ce2ecf7ec04e27c6f330d02eb2aee3b4d01c1d725690747a6aa5c6d784520246af9e92d186ff131a31eaabf9e7a4864104
6
+ metadata.gz: 2ef56f4a0248e446d3063fd6ef92e13743d65a6ecefd523c8b70444f52353667e9b082efb13177a5912ad598425c6382e0ac36321aab231b46f73871e1109a06
7
+ data.tar.gz: 3c483532a0d6dc2d853a172a357a07319466bad2313937a1f57f4f359a2978affeacb80f3e3b5c3df287bc2e07565d692e831dff7564a22cc9a02a1522bab59f
data/README.md CHANGED
@@ -676,12 +676,33 @@ ShopifyGraphql.handle_user_errors(response)
676
676
 
677
677
  ## Built-in Graphql calls
678
678
 
679
+ - `ShopifyGraphql::CurrentShop`:
680
+
681
+ Equivalent to `ShopifyAPI::Shop.current`. Usage example:
682
+
683
+ ```rb
684
+ shop = ShopifyGraphql::CurrentShop.call
685
+ puts shop.name
686
+ ```
687
+
688
+ Or with locales (requires `read_locales` scope):
689
+
690
+ ```rb
691
+ shop = ShopifyGraphql::CurrentShop.call(with_locales: true)
692
+ puts shop.primary_locale
693
+ puts shop.shop_locales
694
+ ```
695
+
679
696
  - `ShopifyGraphql::CancelSubscription`
680
697
  - `ShopifyGraphql::CreateRecurringSubscription`
681
698
  - `ShopifyGraphql::CreateUsageSubscription`
682
699
  - `ShopifyGraphql::GetAppSubscription`
683
700
  - `ShopifyGraphql::UpsertPrivateMetafield`
684
701
  - `ShopifyGraphql::DeletePrivateMetafield`
702
+ - `ShopifyGraphql::CreateBulkMutation`
703
+ - `ShopifyGraphql::CreateBulkQuery`
704
+ - `ShopifyGraphql::CreateStagedUploads`
705
+ - `ShopifyGraphql::GetBulkOperation`
685
706
 
686
707
  Built-in wrappers are located in [`app/graphql/shopify_graphql`](/app/graphql/shopify_graphql/) folder. You can use them directly in your apps or as an example to create your own wrappers.
687
708
 
@@ -709,9 +730,73 @@ response.query_cost # => 1
709
730
  response.points_maxed?(threshold: 100) # => false
710
731
  ```
711
732
 
712
- ## Graphql webhooks
733
+ ## Custom apps
734
+
735
+ In custom apps, if you're using `shopify_app` gem, then the setup is similar public apps. Except `Shop` model which must include class method to make queries to your store:
736
+
737
+ ```rb
738
+ # app/models/shop.rb
739
+ class Shop < ActiveRecord::Base
740
+ include ShopifyApp::ShopSessionStorageWithScopes
741
+
742
+ def self.system
743
+ new(
744
+ shopify_domain: "MYSHOPIFY_DOMAIN",
745
+ shopify_token: "API_ACCESS_TOKEN_FOR_CUSTOM_APP"
746
+ )
747
+ end
748
+ end
749
+ ```
750
+
751
+ Using this method, you should be able to make API calls like this:
752
+
753
+ ```rb
754
+ Shop.system.with_shopify_session do
755
+ GetOrder.call(id: order.shopify_gid)
756
+ end
757
+ ```
758
+
759
+ If you're not using `shopify_app` gem, then you need to setup `ShopifyAPI::Context` manually:
760
+
761
+ ```rb
762
+ # config/initializers/shopify_api.rb
763
+ ShopifyAPI::Context.setup(
764
+ api_key: "XXX",
765
+ api_secret_key: "XXXX",
766
+ scope: "read_orders,read_products",
767
+ is_embedded: false,
768
+ api_version: "2024-07",
769
+ is_private: true,
770
+ )
771
+ ```
772
+
773
+ And create another method in Shop model to make queries to your store:
774
+
775
+ ```rb
776
+ # app/models/shop.rb
777
+ def Shop
778
+ def self.with_shopify_session(&block)
779
+ ShopifyAPI::Auth::Session.temp(
780
+ shop: "MYSHOPIFY_DOMAIN",
781
+ access_token: "API_ACCESS_TOKEN_FOR_CUSTOM_APP",
782
+ &block
783
+ )
784
+ end
785
+ end
786
+ ```
787
+
788
+ Using this method, you should be able to make API calls like this:
789
+
790
+ ```rb
791
+ Shop.with_shopify_session do
792
+ GetOrder.call(id: order.shopify_gid)
793
+ end
794
+ ```
795
+
796
+ ## Graphql webhooks (deprecated)
713
797
 
714
- > Since version 10 `shopify_api` gem includes built-in support for Graphql webhooks. If you are using `shopify_api` version 10 or higher you don't need to use this gem to handle Graphql webhooks. See [`shopify_app` documentation](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/webhooks.md) for more details.
798
+ > [!WARNING]
799
+ > ShopifyGraphql webhooks are deprecated and will be removed in v3.0. Please use `shopify_app` gem for handling webhooks. See [`shopify_app` documentation](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/webhooks.md) for more details.
715
800
 
716
801
  The gem has built-in support for Graphql webhooks (similar to `shopify_app`). To enable it add the following config to `config/initializers/shopify_app.rb`:
717
802
 
@@ -0,0 +1,27 @@
1
+ module ShopifyGraphql
2
+ class CreateBulkMutation
3
+ include Mutation
4
+
5
+ MUTATION = <<~GRAPHQL
6
+ mutation($mutation: String!, $stagedUploadPath: String!) {
7
+ bulkOperationRunMutation(mutation: $mutation, stagedUploadPath: $stagedUploadPath) {
8
+ bulkOperation {
9
+ id
10
+ status
11
+ }
12
+ userErrors {
13
+ field
14
+ message
15
+ }
16
+ }
17
+ }
18
+ GRAPHQL
19
+
20
+ def call(mutation:, staged_upload_path:)
21
+ response = execute(MUTATION, mutation: mutation, stagedUploadPath: staged_upload_path)
22
+ response.data = response.data.bulkOperationRunMutation
23
+ handle_user_errors(response.data)
24
+ response
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module ShopifyGraphql
2
+ class CreateBulkQuery
3
+ include Mutation
4
+
5
+ MUTATION = <<~GRAPHQL
6
+ mutation($query: String!) {
7
+ bulkOperationRunQuery(query: $query) {
8
+ bulkOperation {
9
+ id
10
+ status
11
+ }
12
+ userErrors {
13
+ field
14
+ message
15
+ }
16
+ }
17
+ }
18
+ GRAPHQL
19
+
20
+ def call(query:)
21
+ response = execute(MUTATION, query: query)
22
+ response.data = response.data.bulkOperationRunQuery
23
+ handle_user_errors(response.data)
24
+ response
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ module ShopifyGraphql
2
+ class CreateStagedUploads
3
+ include Mutation
4
+
5
+ MUTATION = <<~GRAPHQL
6
+ mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
7
+ stagedUploadsCreate(input: $input) {
8
+ stagedTargets {
9
+ url
10
+ resourceUrl
11
+ parameters {
12
+ name
13
+ value
14
+ }
15
+ }
16
+ userErrors{
17
+ field,
18
+ message
19
+ }
20
+ }
21
+ }
22
+ GRAPHQL
23
+
24
+ def call(input:)
25
+ response = execute(MUTATION, input: input)
26
+ response.data = response.data.stagedUploadsCreate
27
+ handle_user_errors(response.data)
28
+ response
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,139 @@
1
+ module ShopifyGraphql
2
+ class CurrentShop
3
+ include ShopifyGraphql::Query
4
+
5
+ QUERY = <<~GRAPHQL
6
+ query {
7
+ shop {
8
+ id
9
+ name
10
+ email
11
+ contactEmail
12
+ myshopifyDomain
13
+ primaryDomain {
14
+ host
15
+ }
16
+ #CREATED_AT#
17
+ #UPDATED_AT#
18
+ #SHOP_OWNER_NAME#
19
+ currencyCode
20
+ billingAddress {
21
+ country
22
+ countryCodeV2
23
+ province
24
+ city
25
+ address1
26
+ address2
27
+ zip
28
+ latitude
29
+ longitude
30
+ phone
31
+ }
32
+ timezoneAbbreviation
33
+ ianaTimezone
34
+ plan {
35
+ displayName
36
+ }
37
+ currencyFormats {
38
+ moneyFormat
39
+ moneyInEmailsFormat
40
+ moneyWithCurrencyFormat
41
+ moneyWithCurrencyInEmailsFormat
42
+ }
43
+ weightUnit
44
+ taxShipping
45
+ taxesIncluded
46
+ setupRequired
47
+ checkoutApiSupported
48
+ transactionalSmsDisabled
49
+ enabledPresentmentCurrencies
50
+ #SMS_CONSENT#
51
+ }
52
+ #LOCALES_SUBQUERY#
53
+ }
54
+ GRAPHQL
55
+ LOCALES_SUBQUERY = <<~GRAPHQL
56
+ shopLocales {
57
+ locale
58
+ primary
59
+ }
60
+ GRAPHQL
61
+
62
+ def call(with_locales: false)
63
+ query = prepare_query(QUERY, with_locales: with_locales)
64
+ response = execute(query)
65
+ parse_data(response.data, with_locales: with_locales)
66
+ end
67
+
68
+ private
69
+
70
+ def prepare_query(query, with_locales:)
71
+ query = query.gsub("#LOCALES_SUBQUERY#", with_locales ? LOCALES_SUBQUERY : "")
72
+ if ShopifyAPI::Context.api_version.in?(%w[2024-01 2024-04 2024-07])
73
+ query.gsub!("#SHOP_OWNER_NAME#", "")
74
+ else
75
+ query.gsub!("#SHOP_OWNER_NAME#", "shopOwnerName")
76
+ end
77
+ if ShopifyAPI::Context.api_version.in?(%w[2024-01])
78
+ query.gsub!("#CREATED_AT#", "")
79
+ query.gsub!("#UPDATED_AT#", "")
80
+ query.gsub!("#SMS_CONSENT#", "")
81
+ else
82
+ query.gsub!("#CREATED_AT#", "createdAt")
83
+ query.gsub!("#UPDATED_AT#", "updatedAt")
84
+ query.gsub!("#SMS_CONSENT#", "marketingSmsConsentEnabledAtCheckout")
85
+ end
86
+ query
87
+ end
88
+
89
+ def parse_data(data, with_locales: false)
90
+ plan_display_name = ShopifyGraphql.normalize_plan_display_name(data.shop.plan.displayName)
91
+ plan_name = ShopifyGraphql::DISPLAY_NAME_TO_PLAN[plan_display_name]
92
+ response = OpenStruct.new(
93
+ id: data.shop.id.split("/").last.to_i,
94
+ name: data.shop.name,
95
+ email: data.shop.email,
96
+ customer_email: data.shop.contactEmail,
97
+ myshopify_domain: data.shop.myshopifyDomain,
98
+ domain: data.shop.primaryDomain.host,
99
+ created_at: data.shop.createdAt,
100
+ updated_at: data.shop.updatedAt,
101
+ shop_owner: data.shop.shopOwnerName,
102
+ currency: data.shop.currencyCode,
103
+ country_name: data.shop.billingAddress.country,
104
+ country: data.shop.billingAddress.countryCodeV2,
105
+ country_code: data.shop.billingAddress.countryCodeV2,
106
+ province: data.shop.billingAddress.province,
107
+ province_code: data.shop.billingAddress.provinceCode,
108
+ city: data.shop.billingAddress.city,
109
+ address1: data.shop.billingAddress.address1,
110
+ address2: data.shop.billingAddress.address2,
111
+ zip: data.shop.billingAddress.zip,
112
+ latitude: data.shop.billingAddress.latitude,
113
+ longitude: data.shop.billingAddress.longitude,
114
+ phone: data.shop.billingAddress.phone,
115
+ timezone: data.shop.timezoneAbbreviation,
116
+ iana_timezone: data.shop.ianaTimezone,
117
+ plan_name: plan_name,
118
+ plan_display_name: plan_display_name,
119
+ money_format: data.shop.currencyFormats.moneyFormat,
120
+ money_in_emails_format: data.shop.currencyFormats.moneyInEmailsFormat,
121
+ money_with_currency_format: data.shop.currencyFormats.moneyWithCurrencyFormat,
122
+ money_with_currency_in_emails_format: data.shop.currencyFormats.moneyWithCurrencyInEmailsFormat,
123
+ weight_unit: data.shop.weightUnit,
124
+ tax_shipping: data.shop.taxShipping,
125
+ taxes_included: data.shop.taxesIncluded,
126
+ setup_required: data.shop.setupRequired,
127
+ checkout_api_supported: data.shop.checkoutApiSupported,
128
+ transactional_sms_disabled: data.shop.transactionalSmsDisabled,
129
+ enabled_presentment_currencies: data.shop.enabledPresentmentCurrencies,
130
+ marketing_sms_consent_enabled_at_checkout: data.shop.marketingSmsConsentEnabledAtCheckout
131
+ )
132
+ if with_locales
133
+ response.primary_locale = data.shopLocales.find(&:primary).locale
134
+ response.shop_locales = data.shopLocales.map(&:locale)
135
+ end
136
+ response
137
+ end
138
+ end
139
+ end
@@ -22,7 +22,7 @@ module ShopifyGraphql
22
22
 
23
23
  def parse_data(data)
24
24
  unless data.node
25
- raise ResourceNotFound.new(200, "Subscription not found")
25
+ raise ResourceNotFound.new, "Subscription not found"
26
26
  end
27
27
 
28
28
  OpenStruct.new(
@@ -0,0 +1,44 @@
1
+ module ShopifyGraphql
2
+ class GetBulkOperation
3
+ include Query
4
+
5
+ QUERY = <<~GRAPHQL
6
+ query($id: ID!){
7
+ node(id: $id) {
8
+ ... on BulkOperation {
9
+ id
10
+ status
11
+ errorCode
12
+ createdAt
13
+ completedAt
14
+ fileSize
15
+ url
16
+ }
17
+ }
18
+ }
19
+ GRAPHQL
20
+
21
+ def call(id:)
22
+ response = execute(QUERY, id: id)
23
+ response.data = parse_data(response.data.node)
24
+ response
25
+ end
26
+
27
+ private
28
+
29
+ def parse_data(data)
30
+ unless data
31
+ raise ResourceNotFound.new, "BulkOperation not found"
32
+ end
33
+
34
+ OpenStruct.new(
35
+ id: data.id,
36
+ status: data.status,
37
+ error_code: data.errorCode,
38
+ created_at: Time.find_zone("UTC").parse(data.createdAt),
39
+ completed_at: data.completedAt ? Time.find_zone("UTC").parse(data.completedAt) : nil,
40
+ url: data.url
41
+ )
42
+ end
43
+ end
44
+ end
@@ -1,4 +1,29 @@
1
1
  module ShopifyGraphql
2
+ # Mapping from deprecated plan_name to plan_display_name
3
+ PLAN_TO_DISPLAY_NAME = {
4
+ "trial" => "trial",
5
+ "frozen" => "frozen",
6
+ "fraudulent" => "cancelled",
7
+ "shopify_alumni" => "shopify_alumni",
8
+ "affiliate" => "development",
9
+ "basic" => "basic",
10
+ "professional" => "shopify",
11
+ "npo_full" => "npo_full",
12
+ "shopify_plus" => "shopify_plus",
13
+ "staff" => "staff",
14
+ "unlimited" => "advanced",
15
+ "retail" => "retail",
16
+ "cancelled" => "cancelled",
17
+ "dormant" => "pause_and_build",
18
+ "starter_2022" => "shopify_starter",
19
+ "plus_partner_sandbox" => "shopify_plus_partner_sandbox",
20
+ "paid_trial" => "extended_trial",
21
+ "partner_test" => "developer_preview",
22
+ "open_learning" => "open_learning",
23
+ "staff_business" => "staff_business"
24
+ }
25
+ DISPLAY_NAME_TO_PLAN = PLAN_TO_DISPLAY_NAME.invert
26
+
2
27
  class Client
3
28
  def client
4
29
  @client ||= ShopifyAPI::Clients::Graphql::Admin.new(session: ShopifyAPI::Context.active_session)
@@ -8,11 +33,11 @@ module ShopifyGraphql
8
33
  response = client.query(query: query, variables: variables)
9
34
  Response.new(handle_response(response))
10
35
  rescue ShopifyAPI::Errors::HttpResponseError => e
11
- Response.new(handle_response(e.response))
36
+ Response.new(handle_response(e.response, e))
12
37
  rescue JSON::ParserError => e
13
- raise ServerError.new(e, "Invalid JSON response")
38
+ raise ServerError.new(response: response), "Invalid JSON response: #{e.message}"
14
39
  rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNREFUSED, Errno::ENETUNREACH, Net::ReadTimeout, Net::OpenTimeout, OpenSSL::SSL::SSLError, EOFError => e
15
- raise ServerError.new(e, "Network error")
40
+ raise ServerError.new(response: response), "Network error: #{e.message}"
16
41
  rescue => e
17
42
  if (defined?(Socket::ResolutionError) and e.is_a?(Socket::ResolutionError))
18
43
  raise ServerError.new(response: response), "Network error: #{e.message}"
@@ -29,78 +54,107 @@ module ShopifyGraphql
29
54
  end
30
55
  end
31
56
 
32
- def handle_response(response)
57
+ def handle_response(response, error = nil)
33
58
  case response.code
34
59
  when 200..400
35
- handle_graphql_errors(parsed_body(response))
60
+ handle_graphql_errors(response)
36
61
  when 400
37
- raise BadRequest.new(parsed_body(response), code: response.code)
62
+ raise BadRequest.new(response: response), error.message
38
63
  when 401
39
- raise UnauthorizedAccess.new(parsed_body(response), code: response.code)
64
+ raise UnauthorizedAccess.new(response: response), error.message
40
65
  when 402
41
- raise PaymentRequired.new(parsed_body(response), code: response.code)
66
+ raise PaymentRequired.new(response: response), error.message
42
67
  when 403
43
- raise ForbiddenAccess.new(parsed_body(response), code: response.code)
68
+ raise ForbiddenAccess.new(response: response), error.message
44
69
  when 404
45
- raise ResourceNotFound.new(parsed_body(response), code: response.code)
70
+ raise ResourceNotFound.new(response: response), error.message
46
71
  when 405
47
- raise MethodNotAllowed.new(parsed_body(response), code: response.code)
72
+ raise MethodNotAllowed.new(response: response), error.message
48
73
  when 409
49
- raise ResourceConflict.new(parsed_body(response), code: response.code)
74
+ raise ResourceConflict.new(response: response), error.message
50
75
  when 410
51
- raise ResourceGone.new(parsed_body(response), code: response.code)
76
+ raise ResourceGone.new(response: response), error.message
52
77
  when 412
53
- raise PreconditionFailed.new(parsed_body(response), code: response.code)
78
+ raise PreconditionFailed.new(response: response), error.message
54
79
  when 422
55
- raise ResourceInvalid.new(parsed_body(response), code: response.code)
80
+ raise ResourceInvalid.new(response: response), error.message
56
81
  when 423
57
- raise ShopLocked.new(parsed_body(response), code: response.code)
82
+ raise ShopLocked.new(response: response), error.message
58
83
  when 429, 430
59
- raise TooManyRequests.new(parsed_body(response), code: response.code)
84
+ raise TooManyRequests.new(response: response), error.message
60
85
  when 401...500
61
- raise ClientError.new(parsed_body(response), code: response.code)
86
+ raise ClientError.new(response: response), error.message
62
87
  when 500...600
63
- raise ServerError.new(parsed_body(response), code: response.code)
88
+ raise ServerError.new(response: response), error.message
64
89
  else
65
- raise ConnectionError.new(parsed_body(response), "Unknown response code: #{response.code}")
90
+ raise ConnectionError.new(response: response), error.message
66
91
  end
67
92
  end
68
93
 
69
94
  def handle_graphql_errors(response)
70
- return response if response.errors.blank?
95
+ parsed_body = parsed_body(response)
96
+ if parsed_body.errors.nil? || parsed_body.errors.empty?
97
+ return parsed_body(response)
98
+ end
71
99
 
72
- error = response.errors.first
73
- error_message = error.message
100
+ error = parsed_body.errors.first
74
101
  error_code = error.extensions&.code
75
- error_doc = error.extensions&.documentation
102
+ error_message = generate_error_message(
103
+ message: error.message,
104
+ code: error_code,
105
+ doc: error.extensions&.documentation
106
+ )
76
107
 
77
- case error_code
78
- when "THROTTLED"
79
- raise TooManyRequests.new(response, error_message, code: error_code, doc: error_doc)
80
- when "INTERNAL_SERVER_ERROR"
81
- raise ServerError.new(response, error_message, code: error_code, doc: error_doc)
82
- else
83
- raise ConnectionError.new(response, error_message, code: error_code, doc: error_doc)
84
- end
108
+ exception = case error_code
109
+ when "THROTTLED"
110
+ TooManyRequests.new(response: response)
111
+ when "INTERNAL_SERVER_ERROR"
112
+ ServerError.new(response: response)
113
+ else
114
+ ConnectionError.new(response: response)
115
+ end
116
+ exception.error_code = error_code
117
+ raise exception, error_message
85
118
  end
86
119
 
87
120
  def handle_user_errors(response)
88
121
  return response if response.userErrors.blank?
89
122
 
90
123
  error = response.userErrors.first
91
- error_message = error.message
92
- error_fields = error.field
93
124
  error_code = error.code
125
+ error_message = generate_error_message(
126
+ message: error.message,
127
+ code: error_code,
128
+ fields: error.field,
129
+ )
94
130
 
95
- raise UserError.new(response, error_message, fields: error_fields, code: error_code)
131
+ exception = UserError.new(response: response)
132
+ exception.error_code = error_code
133
+ exception.fields = error.field
134
+ raise exception, error_message
135
+ end
136
+
137
+ def generate_error_message(message: nil, code: nil, doc: nil, fields: nil)
138
+ string = "Failed.".dup
139
+ string << " Response code = #{code}." if code
140
+ string << " Response message = #{message}.".gsub("..", ".") if message
141
+ string << " Documentation = #{doc}." if doc
142
+ string << " Fields = #{fields}." if fields
143
+ string
96
144
  end
97
145
  end
98
146
 
99
147
  class << self
100
- delegate :execute, :handle_user_errors, to: :client
148
+ extend Forwardable
149
+ def_delegators :client, :execute, :handle_user_errors
101
150
 
102
151
  def client
103
152
  Client.new
104
153
  end
154
+
155
+ def normalize_plan_display_name(plan_display_name)
156
+ return if plan_display_name.blank?
157
+ plan_display_name.parameterize(separator: "_")
158
+ end
105
159
  end
106
160
  end
@@ -4,12 +4,17 @@ module ShopifyGraphql
4
4
  include ShopifyGraphql::PayloadVerification
5
5
 
6
6
  included do
7
+ before_action :deprecate_webhooks
7
8
  skip_before_action :verify_authenticity_token, raise: false
8
9
  before_action :verify_request
9
10
  end
10
11
 
11
12
  private
12
13
 
14
+ def deprecate_webhooks
15
+ ShopifyGraphql.deprecator.warn("ShopifyGraphql webhooks are deprecated and will be removed in v3.0. Please use shopify_app gem for handling webhooks.")
16
+ end
17
+
13
18
  def verify_request
14
19
  data = request.raw_post
15
20
  return head(:unauthorized) unless hmac_valid?(data)
@@ -1,4 +1,8 @@
1
1
  module ShopifyGraphql
2
+ def self.deprecator
3
+ @deprecator ||= ActiveSupport::Deprecation.new("3.0", "ShopifyGraphql")
4
+ end
5
+
2
6
  module RedactJobParams
3
7
  private
4
8
 
@@ -1,22 +1,23 @@
1
1
  module ShopifyGraphql
2
- class ConnectionError < StandardError
3
- attr_reader :response, :code, :doc, :fields
4
-
5
- def initialize(response, message = nil, code: nil, doc: nil, fields: nil)
6
- @response = response
7
- @message = message
8
- @code = code
9
- @doc = doc
10
- @fields = fields
11
- end
12
-
13
- def to_s
14
- message = "Failed.".dup
15
- message << " Response code = #{@code}." if @code
16
- message << " Response message = #{@message}." if @message
17
- message << " Documentation = #{@doc}." if @doc
18
- message << " Fields = #{@fields}." if @fields
19
- message
2
+ class ConnectionError < ShopifyAPI::Errors::HttpResponseError
3
+ attr_accessor :error_code, :fields
4
+
5
+ def initialize(response: nil)
6
+ unless response
7
+ empty_response = ShopifyAPI::Clients::HttpResponse.new(code: 200, headers: {}, body: "")
8
+ super(response: empty_response) and return
9
+ end
10
+
11
+ if response.is_a?(ShopifyAPI::Clients::HttpResponse)
12
+ super(response: response)
13
+ else
14
+ response = ShopifyAPI::Clients::HttpResponse.new(
15
+ code: 200,
16
+ headers: {},
17
+ body: response
18
+ )
19
+ super(response: response)
20
+ end
20
21
  end
21
22
  end
22
23
 
@@ -68,11 +69,11 @@ module ShopifyGraphql
68
69
  class TooManyRequests < ClientError # :nodoc:
69
70
  end
70
71
 
71
- # Graphql userErrors
72
- class UserError < ClientError # :nodoc:
73
- end
74
-
75
72
  # 5xx Server Error
76
73
  class ServerError < ConnectionError
77
74
  end
75
+
76
+ # Custom error for Graphql userErrors handling
77
+ class UserError < ConnectionError
78
+ end
78
79
  end
@@ -7,7 +7,8 @@ module ShopifyGraphql::Mutation
7
7
  end
8
8
  end
9
9
 
10
- delegate :execute, :handle_user_errors, to: :client
10
+ extend Forwardable
11
+ def_delegators :client, :execute, :handle_user_errors
11
12
 
12
13
  def client
13
14
  @client ||= ShopifyGraphql::Client.new
@@ -7,7 +7,8 @@ module ShopifyGraphql::Query
7
7
  end
8
8
  end
9
9
 
10
- delegate :execute, :handle_user_errors, to: :client
10
+ extend Forwardable
11
+ def_delegators :client, :execute, :handle_user_errors
11
12
 
12
13
  def client
13
14
  @client ||= ShopifyGraphql::Client.new
@@ -3,7 +3,8 @@ module ShopifyGraphql
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  class_methods do
6
- delegate :execute, :handle_user_errors, to: :client
6
+ extend Forwardable
7
+ def_delegators :client, :execute, :handle_user_errors
7
8
 
8
9
  def client
9
10
  ShopifyGraphql::Client.new
@@ -1,3 +1,3 @@
1
1
  module ShopifyGraphql
2
- VERSION = "1.2.7"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,8 +1,11 @@
1
1
  require 'shopify_api'
2
+ require 'active_support'
2
3
 
3
4
  require 'shopify_graphql/client'
4
5
  require 'shopify_graphql/configuration'
5
- require 'shopify_graphql/engine'
6
+ if defined?(Rails)
7
+ require 'shopify_graphql/engine'
8
+ end
6
9
  require 'shopify_graphql/exceptions'
7
10
  require 'shopify_graphql/mutation'
8
11
  require 'shopify_graphql/query'
@@ -15,9 +18,11 @@ require 'shopify_graphql/controller_concerns/payload_verification'
15
18
  require 'shopify_graphql/controller_concerns/webhook_verification'
16
19
 
17
20
  # jobs
18
- require 'shopify_graphql/jobs/create_webhooks_job'
19
- require 'shopify_graphql/jobs/destroy_webhooks_job'
20
- require 'shopify_graphql/jobs/update_webhooks_job'
21
+ if defined?(Rails)
22
+ require 'shopify_graphql/jobs/create_webhooks_job'
23
+ require 'shopify_graphql/jobs/destroy_webhooks_job'
24
+ require 'shopify_graphql/jobs/update_webhooks_job'
25
+ end
21
26
 
22
27
  # managers
23
28
  require 'shopify_graphql/managers/webhooks_manager'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify_graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.7
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kirill Platonov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
11
+ date: 2024-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,28 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0
19
+ version: 6.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.0
26
+ version: 6.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 6.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 6.1.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: shopify_api
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - ">="
32
46
  - !ruby/object:Gem::Version
33
- version: '10.0'
47
+ version: '13.4'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: '13.4'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: shopify_app
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -64,10 +78,15 @@ files:
64
78
  - app/controllers/shopify_graphql/graphql_webhooks_controller.rb
65
79
  - app/graphql/shopify_graphql/app_subscription_fields.rb
66
80
  - app/graphql/shopify_graphql/cancel_subscription.rb
81
+ - app/graphql/shopify_graphql/create_bulk_mutation.rb
82
+ - app/graphql/shopify_graphql/create_bulk_query.rb
67
83
  - app/graphql/shopify_graphql/create_recurring_subscription.rb
84
+ - app/graphql/shopify_graphql/create_staged_uploads.rb
68
85
  - app/graphql/shopify_graphql/create_usage_subscription.rb
86
+ - app/graphql/shopify_graphql/current_shop.rb
69
87
  - app/graphql/shopify_graphql/delete_private_metafield.rb
70
88
  - app/graphql/shopify_graphql/get_app_subscription.rb
89
+ - app/graphql/shopify_graphql/get_bulk_operation.rb
71
90
  - app/graphql/shopify_graphql/upsert_private_metafield.rb
72
91
  - config/routes.rb
73
92
  - lib/shopify_graphql.rb
@@ -102,14 +121,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
121
  requirements:
103
122
  - - ">="
104
123
  - !ruby/object:Gem::Version
105
- version: 2.7.0
124
+ version: '3.0'
106
125
  required_rubygems_version: !ruby/object:Gem::Requirement
107
126
  requirements:
108
127
  - - ">="
109
128
  - !ruby/object:Gem::Version
110
129
  version: '0'
111
130
  requirements: []
112
- rubygems_version: 3.4.3
131
+ rubygems_version: 3.5.11
113
132
  signing_key:
114
133
  specification_version: 4
115
134
  summary: Less painful way to work with Shopify Graphql API in Ruby.