shopify_graphql 1.2.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a20f7b85f9a4a22fd1c3ea0509ec496f3447a2764fedf105539cab20274ed221
4
- data.tar.gz: 966022527dd821e837c200d6c1df8ca84236b05ed5e311c6ac13dbabe00322f9
3
+ metadata.gz: fe9ea3cbb7c46d86fe1281d9658cc1de370db1b306b29aa331c1c8ac9ae94f0d
4
+ data.tar.gz: ab91936f744cd3c40ee1b81952426a839e26fb3fd8b9ca55defa5248c22ed812
5
5
  SHA512:
6
- metadata.gz: 02c0027937db4125f3a1146275a999e1c6657ebe28682d5e0da81d34fcebac78796877abc4e7d1572de84599a82033d2140cabd8afbdd9b39951e428a9d4644f
7
- data.tar.gz: 4eeb9be4a243c5bcba638857a6bfa29f28e20a94ba1d3aa236ac30fdf7a2a6587bd4d74a6b7a53349118a60072458fc87fc255c16560b76b07c0d64c33e2ae13
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,17 @@ 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")
14
- rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNREFUSED, Errno::ENETUNREACH, Net::ReadTimeout, Net::OpenTimeout, OpenSSL::SSL::SSLError, EOFError, Socket::ResolutionError => e
15
- raise ServerError.new(e, "Network error")
38
+ raise ServerError.new(response: response), "Invalid JSON response: #{e.message}"
39
+ rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNREFUSED, Errno::ENETUNREACH, Net::ReadTimeout, Net::OpenTimeout, OpenSSL::SSL::SSLError, EOFError => e
40
+ raise ServerError.new(response: response), "Network error: #{e.message}"
41
+ rescue => e
42
+ if (defined?(Socket::ResolutionError) and e.is_a?(Socket::ResolutionError))
43
+ raise ServerError.new(response: response), "Network error: #{e.message}"
44
+ else
45
+ raise e
46
+ end
16
47
  end
17
48
 
18
49
  def parsed_body(response)
@@ -23,78 +54,107 @@ module ShopifyGraphql
23
54
  end
24
55
  end
25
56
 
26
- def handle_response(response)
57
+ def handle_response(response, error = nil)
27
58
  case response.code
28
59
  when 200..400
29
- handle_graphql_errors(parsed_body(response))
60
+ handle_graphql_errors(response)
30
61
  when 400
31
- raise BadRequest.new(parsed_body(response), code: response.code)
62
+ raise BadRequest.new(response: response), error.message
32
63
  when 401
33
- raise UnauthorizedAccess.new(parsed_body(response), code: response.code)
64
+ raise UnauthorizedAccess.new(response: response), error.message
34
65
  when 402
35
- raise PaymentRequired.new(parsed_body(response), code: response.code)
66
+ raise PaymentRequired.new(response: response), error.message
36
67
  when 403
37
- raise ForbiddenAccess.new(parsed_body(response), code: response.code)
68
+ raise ForbiddenAccess.new(response: response), error.message
38
69
  when 404
39
- raise ResourceNotFound.new(parsed_body(response), code: response.code)
70
+ raise ResourceNotFound.new(response: response), error.message
40
71
  when 405
41
- raise MethodNotAllowed.new(parsed_body(response), code: response.code)
72
+ raise MethodNotAllowed.new(response: response), error.message
42
73
  when 409
43
- raise ResourceConflict.new(parsed_body(response), code: response.code)
74
+ raise ResourceConflict.new(response: response), error.message
44
75
  when 410
45
- raise ResourceGone.new(parsed_body(response), code: response.code)
76
+ raise ResourceGone.new(response: response), error.message
46
77
  when 412
47
- raise PreconditionFailed.new(parsed_body(response), code: response.code)
78
+ raise PreconditionFailed.new(response: response), error.message
48
79
  when 422
49
- raise ResourceInvalid.new(parsed_body(response), code: response.code)
80
+ raise ResourceInvalid.new(response: response), error.message
50
81
  when 423
51
- raise ShopLocked.new(parsed_body(response), code: response.code)
82
+ raise ShopLocked.new(response: response), error.message
52
83
  when 429, 430
53
- raise TooManyRequests.new(parsed_body(response), code: response.code)
84
+ raise TooManyRequests.new(response: response), error.message
54
85
  when 401...500
55
- raise ClientError.new(parsed_body(response), code: response.code)
86
+ raise ClientError.new(response: response), error.message
56
87
  when 500...600
57
- raise ServerError.new(parsed_body(response), code: response.code)
88
+ raise ServerError.new(response: response), error.message
58
89
  else
59
- raise ConnectionError.new(parsed_body(response), "Unknown response code: #{response.code}")
90
+ raise ConnectionError.new(response: response), error.message
60
91
  end
61
92
  end
62
93
 
63
94
  def handle_graphql_errors(response)
64
- 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
65
99
 
66
- error = response.errors.first
67
- error_message = error.message
100
+ error = parsed_body.errors.first
68
101
  error_code = error.extensions&.code
69
- 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
+ )
70
107
 
71
- case error_code
72
- when "THROTTLED"
73
- raise TooManyRequests.new(response, error_message, code: error_code, doc: error_doc)
74
- when "INTERNAL_SERVER_ERROR"
75
- raise ServerError.new(response, error_message, code: error_code, doc: error_doc)
76
- else
77
- raise ConnectionError.new(response, error_message, code: error_code, doc: error_doc)
78
- 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
79
118
  end
80
119
 
81
120
  def handle_user_errors(response)
82
121
  return response if response.userErrors.blank?
83
122
 
84
123
  error = response.userErrors.first
85
- error_message = error.message
86
- error_fields = error.field
87
124
  error_code = error.code
125
+ error_message = generate_error_message(
126
+ message: error.message,
127
+ code: error_code,
128
+ fields: error.field,
129
+ )
130
+
131
+ exception = UserError.new(response: response)
132
+ exception.error_code = error_code
133
+ exception.fields = error.field
134
+ raise exception, error_message
135
+ end
88
136
 
89
- raise UserError.new(response, error_message, fields: error_fields, code: error_code)
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
90
144
  end
91
145
  end
92
146
 
93
147
  class << self
94
- delegate :execute, :handle_user_errors, to: :client
148
+ extend Forwardable
149
+ def_delegators :client, :execute, :handle_user_errors
95
150
 
96
151
  def client
97
152
  Client.new
98
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
99
159
  end
100
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.6"
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.6
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-06-11 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.