shopify_api-graphql-tiny 0.1.0 → 0.2.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 +4 -4
- data/.env.template +5 -0
- data/.github/workflows/ci.yml +2 -1
- data/Changes +4 -0
- data/README.md +151 -2
- data/lib/shopify_api/graphql/tiny/version.rb +3 -1
- data/lib/shopify_api/graphql/tiny.rb +201 -4
- data/shopify_api-graphql-tiny.gemspec +7 -1
- metadata +10 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be69f222bb991d00b37c44d8aea2ad9caee713527ce23c60121a401d8d2a8b39
|
|
4
|
+
data.tar.gz: 5a35aaada946e0f0ef1dc50ea7962da2252a7f70a111a911f660b1c8eab3a79a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be94db6e155cc11d0136a229e6ee728ac808c655896f5489a657fc4ba82b7d5ab8403989bc356cfaaa617766077220e8234c60ff6d9aa9a651d484490cb161c3
|
|
7
|
+
data.tar.gz: 166c19ddde4a76d8d216bffac16d3844c9add39f9884eb70adac3477ce5b222e19cba820c1bae1204f58424239be38a1ec063d8e75a977f337f0d5df5afc6452
|
data/.env.template
CHANGED
data/.github/workflows/ci.yml
CHANGED
|
@@ -11,10 +11,11 @@ jobs:
|
|
|
11
11
|
SHOPIFY_DOMAIN: "${{ secrets.SHOPIFY_DOMAIN }}"
|
|
12
12
|
SHOPIFY_TOKEN: "${{ secrets.SHOPIFY_TOKEN }}"
|
|
13
13
|
SHOPIFY_CUSTOMER_ID: "${{ secrets.SHOPIFY_CUSTOMER_ID }}"
|
|
14
|
+
SHOPIFY_PRODUCT_ID: "${{ secrets.SHOPIFY_PRODUCT_ID }}"
|
|
14
15
|
|
|
15
16
|
strategy:
|
|
16
17
|
matrix:
|
|
17
|
-
ruby: ["3.1", "3.0", "2.7.2", "2.6.6", "2.5.8", "2.4.10"]
|
|
18
|
+
ruby: ["3.2", "3.1", "3.0", "2.7.2", "2.6.6", "2.5.8", "2.4.10"]
|
|
18
19
|
|
|
19
20
|
steps:
|
|
20
21
|
- uses: actions/checkout@v2
|
data/Changes
CHANGED
data/README.md
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
# ShopifyAPI::GraphQL::Tiny
|
|
2
2
|
|
|
3
|
-
Lightweight, no-nonsense, Shopify GraphQL Admin API client with built-in retry.
|
|
3
|
+
Lightweight, no-nonsense, Shopify GraphQL Admin API client with built-in pagination and retry.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/ScreenStaring/shopify_api-graphql-tiny/actions)
|
|
6
6
|
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's `Gemfile`:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem "shopify_api-graphql-tiny"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
bundle
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install it yourself as:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
gem install shopify_api-graphql-tiny
|
|
25
|
+
```
|
|
26
|
+
|
|
7
27
|
## Usage
|
|
8
28
|
|
|
9
29
|
```rb
|
|
10
30
|
require "shopify_api/graphql/tiny"
|
|
11
31
|
|
|
12
32
|
gql = ShopifyAPI::GraphQL::Tiny.new("my-shop", token)
|
|
33
|
+
|
|
34
|
+
# Automatically retried
|
|
13
35
|
result = gql.execute(<<-GQL, :id => "gid://shopify/Customer/1283599123")
|
|
14
36
|
query findCustomer($id: ID!) {
|
|
15
37
|
customer(id: $id) {
|
|
@@ -33,6 +55,8 @@ p customer["tags"]
|
|
|
33
55
|
p customer.dig("metafields", "edges", 0, "node")["value"]
|
|
34
56
|
|
|
35
57
|
updates = { :id => customer["id"], :tags => customer["tags"] + %w[foo bar] }
|
|
58
|
+
|
|
59
|
+
# Automatically retried as well
|
|
36
60
|
result = gql.execute(<<-GQL, :input => updates)
|
|
37
61
|
mutation customerUpdate($input: CustomerInput!) {
|
|
38
62
|
customerUpdate(input: $input) {
|
|
@@ -50,7 +74,131 @@ GQL
|
|
|
50
74
|
p result.dig("data", "customerUpdate", "userErrors")
|
|
51
75
|
```
|
|
52
76
|
|
|
53
|
-
|
|
77
|
+
### Pagination
|
|
78
|
+
|
|
79
|
+
In addition to built-in request retry `ShopifyAPI::GraphQL::Tiny` also builds in support for pagination.
|
|
80
|
+
|
|
81
|
+
Using pagination requires you to include [the Shopify `PageInfo` object](https://shopify.dev/api/admin-graphql/2022-10/objects/PageInfo)
|
|
82
|
+
in your queries and wrap them in a function that accepts a page/cursor argument.
|
|
83
|
+
|
|
84
|
+
The pager's `#execute` is like the non-paginated `#execute` method and accepts additional, non-pagination query arguments:
|
|
85
|
+
|
|
86
|
+
```rb
|
|
87
|
+
gql = ShopifyAPI::GraphQL::Tiny.new("my-shop", token)
|
|
88
|
+
pager = gql.paginate
|
|
89
|
+
pager.execute(query, :foo => 123)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
And it accepts a block which will be passed each page returned by the query:
|
|
93
|
+
|
|
94
|
+
```rb
|
|
95
|
+
pager.execute(query, :foo => 123) do |page|
|
|
96
|
+
# do something with each page
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### `after` Pagination
|
|
101
|
+
|
|
102
|
+
To use `after` pagination, i.e., to paginate forward, your query must:
|
|
103
|
+
|
|
104
|
+
- Make the page/cursor argument optional
|
|
105
|
+
- Include `PageInfo`'s `hasNextPage` and `endCursor` fields
|
|
106
|
+
|
|
107
|
+
For example:
|
|
108
|
+
|
|
109
|
+
```rb
|
|
110
|
+
FIND_ORDERS = <<-GQL
|
|
111
|
+
query findOrders($after: String) {
|
|
112
|
+
orders(first: 10 after: $after) {
|
|
113
|
+
pageInfo {
|
|
114
|
+
hasNextPage
|
|
115
|
+
endCursor
|
|
116
|
+
}
|
|
117
|
+
edges {
|
|
118
|
+
node {
|
|
119
|
+
id
|
|
120
|
+
email
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
GQL
|
|
126
|
+
|
|
127
|
+
pager = gql.paginate # This is the same as gql.paginate(:after)
|
|
128
|
+
pager.execute(FIND_ORDERS) do |page|
|
|
129
|
+
orders = page.dig("data", "orders", "edges")
|
|
130
|
+
orders.each do |order|
|
|
131
|
+
# ...
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
By default it is assumed your GraphQL query uses a variable named `$after`. You can specify a different name using the `:variable`
|
|
137
|
+
option:
|
|
138
|
+
|
|
139
|
+
```rb
|
|
140
|
+
pager = gql.paginate(:after, :variable => "yourVariable")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### `before` Pagination
|
|
144
|
+
|
|
145
|
+
To use `before` pagination, i.e. to paginate backward, your query must:
|
|
146
|
+
|
|
147
|
+
- Make the page/cursor argument **required**
|
|
148
|
+
- Include the `PageInfo`'s `hasPreviousPage` and `startCursor` fields
|
|
149
|
+
- Specify the `:before` argument to `#paginate`
|
|
150
|
+
|
|
151
|
+
For example:
|
|
152
|
+
|
|
153
|
+
```rb
|
|
154
|
+
FIND_ORDERS = <<-GQL
|
|
155
|
+
query findOrders($before: String) {
|
|
156
|
+
orders(last: 10 before: $before) {
|
|
157
|
+
pageInfo {
|
|
158
|
+
hasPreviousPage
|
|
159
|
+
startCursor
|
|
160
|
+
}
|
|
161
|
+
edges {
|
|
162
|
+
node {
|
|
163
|
+
id
|
|
164
|
+
email
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
GQL
|
|
170
|
+
|
|
171
|
+
pager = gql.paginate(:before)
|
|
172
|
+
pager.execute(FIND_ORDERS) do |page|
|
|
173
|
+
# ...
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
By default it is assumed your GraphQL query uses a variable named `$before`. You can specify a different name using the `:variable`
|
|
178
|
+
option:
|
|
179
|
+
|
|
180
|
+
```rb
|
|
181
|
+
pager = gql.paginate(:before, :variable => "yourVariable")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Response Pagination Data
|
|
185
|
+
|
|
186
|
+
By default `ShopifyAPI::GraphQL::Tiny` will use the first `pageInfo` block with a next or previous page it finds
|
|
187
|
+
in the GraphQL response. If necessary you can specify an explicit location for the `pageInfo` block:
|
|
188
|
+
|
|
189
|
+
```rb
|
|
190
|
+
pager = gql.paginate(:after => %w[some path to it])
|
|
191
|
+
pager.execute(query) { |page| }
|
|
192
|
+
|
|
193
|
+
pager = gql.paginate(:after => ->(data) { data.dig("some", "path", "to", "it") })
|
|
194
|
+
pager.execute(query) { |page| }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The `"data"` and `"pageInfo"` keys are automatically added if not provided.
|
|
198
|
+
|
|
199
|
+
### Automatically Retrying Failed Requests
|
|
200
|
+
|
|
201
|
+
See [the docs](https://rubydoc.info/gems/shopify_api-graphql-tiny) for more information.
|
|
54
202
|
|
|
55
203
|
## Testing
|
|
56
204
|
|
|
@@ -59,6 +207,7 @@ See [the docs](https://rdoc.info/gems/shopify_api-graphql-tiny) for complete doc
|
|
|
59
207
|
## See Also
|
|
60
208
|
|
|
61
209
|
- [Shopify Dev Tools](https://github.com/ScreenStaring/shopify-dev-tools) - Command-line program to assist with the development and/or maintenance of Shopify apps and stores
|
|
210
|
+
- [Shopify ID Export](https://github.com/ScreenStaring/shopify_id_export/) Dump Shopify product and variant IDs —along with other identifiers— to a CSV or JSON file
|
|
62
211
|
- [ShopifyAPIRetry](https://github.com/ScreenStaring/shopify_api_retry) - Retry a ShopifyAPI request if rate-limited or other errors occur (REST and GraphQL APIs)
|
|
63
212
|
|
|
64
213
|
## License
|
|
@@ -43,6 +43,8 @@ module ShopifyAPI
|
|
|
43
43
|
QUERY_COST_HEADER = "X-GraphQL-Cost-Include-Fields"
|
|
44
44
|
|
|
45
45
|
DEFAULT_HEADERS = { "Content-Type" => "application/json" }.freeze
|
|
46
|
+
|
|
47
|
+
# Retry rules to be used for all instances if no rules are specified via the +:retry+ option when creating an instance
|
|
46
48
|
DEFAULT_RETRY_OPTIONS = {
|
|
47
49
|
ConnectionError => { :wait => 3, :tries => 20 },
|
|
48
50
|
GraphQLError => { :wait => 3, :tries => 20 },
|
|
@@ -84,6 +86,10 @@ module ShopifyAPI
|
|
|
84
86
|
@headers[QUERY_COST_HEADER] = "true" if retry?
|
|
85
87
|
|
|
86
88
|
@endpoint = URI(sprintf(ENDPOINT, @domain, !@options[:version].to_s.strip.empty? ? "/#{@options[:version]}" : ""))
|
|
89
|
+
|
|
90
|
+
if @options[:retry].is_a?(Hash)
|
|
91
|
+
warn "DEPRECATION WARNING from #{self.class}: specifying retry options as a Hash via the :retry option is deprecated and will be removed in v1.0"
|
|
92
|
+
end
|
|
87
93
|
end
|
|
88
94
|
|
|
89
95
|
#
|
|
@@ -96,21 +102,71 @@ module ShopifyAPI
|
|
|
96
102
|
#
|
|
97
103
|
# === Errors
|
|
98
104
|
#
|
|
99
|
-
# ConnectionError, HTTPError, RateLimitError, GraphQLError
|
|
105
|
+
# ArgumentError, ConnectionError, HTTPError, RateLimitError, GraphQLError
|
|
100
106
|
#
|
|
101
|
-
# * An HTTPError is raised of the response does not have 200 status code
|
|
102
|
-
# * A RateLimitError is raised if rate-limited and retries are disabled or if still
|
|
103
|
-
#
|
|
107
|
+
# * An ShopifyAPI::GraphQL::Tiny::HTTPError is raised of the response does not have 200 status code
|
|
108
|
+
# * A ShopifyAPI::GraphQL::Tiny::RateLimitError is raised if rate-limited and retries are disabled or if still
|
|
109
|
+
# rate-limited after the configured number of retry attempts
|
|
110
|
+
# * A ShopifyAPI::GraphQL::Tiny::GraphQLError is raised if the response contains an +errors+ property that is
|
|
111
|
+
# not a rate-limit error
|
|
104
112
|
#
|
|
105
113
|
# === Returns
|
|
106
114
|
#
|
|
107
115
|
# [Hash] The GraphQL response. Unmodified.
|
|
108
116
|
|
|
109
117
|
def execute(q, variables = nil)
|
|
118
|
+
raise ArgumentError, "query required" if q.nil? || q.to_s.strip.empty?
|
|
119
|
+
|
|
110
120
|
config = retry? ? @options[:retry] || DEFAULT_RETRY_OPTIONS : {}
|
|
111
121
|
ShopifyAPIRetry::GraphQL.retry(config) { post(q, variables) }
|
|
112
122
|
end
|
|
113
123
|
|
|
124
|
+
##
|
|
125
|
+
# Create a pager to execute a paginated query:
|
|
126
|
+
#
|
|
127
|
+
# pager = gql.paginate # This is the same as gql.paginate(:after)
|
|
128
|
+
# pager.execute(query, :id => id) do |page|
|
|
129
|
+
# page.dig("data", "product", "title")
|
|
130
|
+
# end
|
|
131
|
+
#
|
|
132
|
+
# The block is called for each page.
|
|
133
|
+
#
|
|
134
|
+
# Using pagination requires you to include the
|
|
135
|
+
# {PageInfo}[https://shopify.dev/api/admin-graphql/2022-10/objects/PageInfo]
|
|
136
|
+
# object in your queries and wrap them in a function that accepts a page/cursor argument.
|
|
137
|
+
# See the README for more information.
|
|
138
|
+
#
|
|
139
|
+
# === Arguments
|
|
140
|
+
#
|
|
141
|
+
# [direction (Symbol)] The direction to paginate, either +:after+ or +:before+. Optional, defaults to +:after:+
|
|
142
|
+
# [options (Hash)] Pagination options. Optional.
|
|
143
|
+
#
|
|
144
|
+
# === Options
|
|
145
|
+
#
|
|
146
|
+
# [:after (Array|Proc)] The location of {PageInfo}[https://shopify.dev/api/admin-graphql/2022-10/objects/PageInfo]
|
|
147
|
+
# block.
|
|
148
|
+
#
|
|
149
|
+
# An +Array+ will be passed directly to <code>Hash#dig</code>. A +TypeError+ resulting
|
|
150
|
+
# from the +#dig+ call will be raised as an +ArgumentError+.
|
|
151
|
+
#
|
|
152
|
+
# The <code>"data"</code> and <code>"pageInfo"</code> keys are automatically added if not provided.
|
|
153
|
+
#
|
|
154
|
+
# A +Proc+ must accept the GraphQL response +Hash+ as its argument and must return the
|
|
155
|
+
# +pageInfo+ block to use for pagination.
|
|
156
|
+
#
|
|
157
|
+
# [:before (Array|Proc)] See the +:after+ option
|
|
158
|
+
# [:variable (String)] Name of the GraphQL variable to use as the "page" argument.
|
|
159
|
+
# Defaults to <code>"before"</code> or <code>"after"</code>, depending on the pagination
|
|
160
|
+
# direction.
|
|
161
|
+
#
|
|
162
|
+
# === Errors
|
|
163
|
+
#
|
|
164
|
+
# ArgumentError
|
|
165
|
+
|
|
166
|
+
def paginate(*options)
|
|
167
|
+
Pager.new(self, options)
|
|
168
|
+
end
|
|
169
|
+
|
|
114
170
|
private
|
|
115
171
|
|
|
116
172
|
def retry?
|
|
@@ -166,6 +222,147 @@ module ShopifyAPI
|
|
|
166
222
|
raise GraphQLError.new(prefix + errors, json)
|
|
167
223
|
end
|
|
168
224
|
end
|
|
225
|
+
|
|
226
|
+
class Pager # :nodoc:
|
|
227
|
+
NEXT_PAGE_KEYS = {
|
|
228
|
+
:before => %w[hasPreviousPage startCursor].freeze,
|
|
229
|
+
:after => %w[hasNextPage endCursor].freeze
|
|
230
|
+
}.freeze
|
|
231
|
+
|
|
232
|
+
def initialize(gql, *options)
|
|
233
|
+
@gql = gql
|
|
234
|
+
@options = normalize_options(options)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def execute(q, variables = nil)
|
|
238
|
+
unless pagination_variable_exists?(q)
|
|
239
|
+
raise ArgumentError, "query does not contain the pagination variable '#{@options[:variable]}'"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
variables ||= {}
|
|
243
|
+
pagination_finder = @options[@options[:direction]]
|
|
244
|
+
|
|
245
|
+
loop do
|
|
246
|
+
page = @gql.execute(q, variables)
|
|
247
|
+
|
|
248
|
+
yield page
|
|
249
|
+
|
|
250
|
+
cursor = pagination_finder[page]
|
|
251
|
+
break unless cursor
|
|
252
|
+
|
|
253
|
+
next_page_variables = variables.dup
|
|
254
|
+
next_page_variables[@options[:variable]] = cursor
|
|
255
|
+
#break unless next_page_variables != variables
|
|
256
|
+
|
|
257
|
+
variables = next_page_variables
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
private
|
|
262
|
+
|
|
263
|
+
def normalize_options(options)
|
|
264
|
+
normalized = {}
|
|
265
|
+
|
|
266
|
+
options.flatten!
|
|
267
|
+
options.each do |option|
|
|
268
|
+
case option
|
|
269
|
+
when Hash
|
|
270
|
+
normalized.merge!(normalize_hash_option(option))
|
|
271
|
+
when *NEXT_PAGE_KEYS.keys
|
|
272
|
+
normalized[:direction] = option
|
|
273
|
+
else
|
|
274
|
+
raise ArgumentError, "invalid pagination option #{option}"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
normalized[:direction] ||= :after
|
|
279
|
+
normalized[normalized[:direction]] ||= method(:default_pagination_finder)
|
|
280
|
+
|
|
281
|
+
normalized[:variable] ||= normalized[:direction].to_s
|
|
282
|
+
normalized[:variable] = normalized[:variable].sub(%r{\A\$}, "")
|
|
283
|
+
|
|
284
|
+
normalized
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def normalize_hash_option(option)
|
|
288
|
+
normalized = option.dup
|
|
289
|
+
|
|
290
|
+
NEXT_PAGE_KEYS.each do |key, _|
|
|
291
|
+
next unless option.include?(key)
|
|
292
|
+
|
|
293
|
+
normalized[:direction] = key
|
|
294
|
+
|
|
295
|
+
case option[key]
|
|
296
|
+
when Proc
|
|
297
|
+
normalized[key] = ->(data) { extract_cursor(option[key][data]) }
|
|
298
|
+
when Array
|
|
299
|
+
path = pagination_path(option[key])
|
|
300
|
+
normalized[key] = ->(data) do
|
|
301
|
+
begin
|
|
302
|
+
extract_cursor(data.dig(*path))
|
|
303
|
+
rescue TypeError => e
|
|
304
|
+
# Use original path in error as not to confuse
|
|
305
|
+
raise ArgumentError, "invalid pagination path #{option[key]}: #{e}"
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
else
|
|
309
|
+
raise ArgumentError, "invalid pagination locator #{option[key]}"
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
normalized
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def pagination_path(user_path)
|
|
317
|
+
path = user_path.dup
|
|
318
|
+
|
|
319
|
+
# No need for this, we check for this key ourselves
|
|
320
|
+
path.pop if path[-1] == "pageInfo"
|
|
321
|
+
|
|
322
|
+
# Must always include this (sigh)
|
|
323
|
+
path.unshift("data") if path[0] != "data"
|
|
324
|
+
|
|
325
|
+
path
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def pagination_variable_exists?(query)
|
|
329
|
+
name = Regexp.quote(@options[:variable])
|
|
330
|
+
query.match?(%r{\$#{name}\s*:})
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def extract_cursor(data)
|
|
334
|
+
return unless data.is_a?(Hash)
|
|
335
|
+
|
|
336
|
+
has_next, next_cursor = NEXT_PAGE_KEYS[@options[:direction]]
|
|
337
|
+
|
|
338
|
+
pi = data["pageInfo"]
|
|
339
|
+
return unless pi && pi[has_next]
|
|
340
|
+
|
|
341
|
+
pi[next_cursor]
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def default_pagination_finder(data)
|
|
345
|
+
cursor = nil
|
|
346
|
+
|
|
347
|
+
case data
|
|
348
|
+
when Hash
|
|
349
|
+
cursor = extract_cursor(data)
|
|
350
|
+
return cursor if cursor
|
|
351
|
+
|
|
352
|
+
data.values.each do |v|
|
|
353
|
+
cursor = default_pagination_finder(v)
|
|
354
|
+
break if cursor
|
|
355
|
+
end
|
|
356
|
+
when Array
|
|
357
|
+
data.each do |v|
|
|
358
|
+
cursor = default_pagination_finder(v)
|
|
359
|
+
break if cursor
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
cursor
|
|
364
|
+
end
|
|
365
|
+
end
|
|
169
366
|
end
|
|
170
367
|
|
|
171
368
|
GQL = GraphQL
|
|
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["Skye Shaw"]
|
|
10
10
|
spec.email = ["skye.shaw@gmail.com"]
|
|
11
11
|
|
|
12
|
-
spec.summary = %q{Lightweight, no-nonsense, Shopify Admin API
|
|
12
|
+
spec.summary = %q{Lightweight, no-nonsense, Shopify GraphQL Admin API client with built-in pagination and retry}
|
|
13
13
|
spec.homepage = "https://github.com/ScreenStaring/shopify_api-graphql-tiny"
|
|
14
14
|
spec.license = "MIT"
|
|
15
15
|
|
|
@@ -21,6 +21,12 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.bindir = "exe"
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
23
23
|
spec.require_paths = ["lib"]
|
|
24
|
+
spec.metadata = {
|
|
25
|
+
"bug_tracker_uri" => "https://github.com/ScreenStaring/shopify_api-graphql-tiny/issues",
|
|
26
|
+
"changelog_uri" => "https://github.com/ScreenStaring/shopify_api-graphql-tiny/blob/master/Changes",
|
|
27
|
+
"documentation_uri" => "https://rubydoc.info/gems/shopify_api-graphql-tiny",
|
|
28
|
+
"source_code_uri" => "https://github.com/ScreenStaring/shopify_api-graphql-tiny",
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
spec.add_dependency "shopify_api_retry", "~> 0.2"
|
|
26
32
|
spec.add_development_dependency "webmock", "~> 3.0"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shopify_api-graphql-tiny
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Skye Shaw
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2026-01-20 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: shopify_api_retry
|
|
@@ -80,7 +79,6 @@ dependencies:
|
|
|
80
79
|
- - "~>"
|
|
81
80
|
- !ruby/object:Gem::Version
|
|
82
81
|
version: '3.0'
|
|
83
|
-
description:
|
|
84
82
|
email:
|
|
85
83
|
- skye.shaw@gmail.com
|
|
86
84
|
executables: []
|
|
@@ -104,8 +102,11 @@ files:
|
|
|
104
102
|
homepage: https://github.com/ScreenStaring/shopify_api-graphql-tiny
|
|
105
103
|
licenses:
|
|
106
104
|
- MIT
|
|
107
|
-
metadata:
|
|
108
|
-
|
|
105
|
+
metadata:
|
|
106
|
+
bug_tracker_uri: https://github.com/ScreenStaring/shopify_api-graphql-tiny/issues
|
|
107
|
+
changelog_uri: https://github.com/ScreenStaring/shopify_api-graphql-tiny/blob/master/Changes
|
|
108
|
+
documentation_uri: https://rubydoc.info/gems/shopify_api-graphql-tiny
|
|
109
|
+
source_code_uri: https://github.com/ScreenStaring/shopify_api-graphql-tiny
|
|
109
110
|
rdoc_options: []
|
|
110
111
|
require_paths:
|
|
111
112
|
- lib
|
|
@@ -120,10 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
120
121
|
- !ruby/object:Gem::Version
|
|
121
122
|
version: '0'
|
|
122
123
|
requirements: []
|
|
123
|
-
|
|
124
|
-
rubygems_version: 2.7.6
|
|
125
|
-
signing_key:
|
|
124
|
+
rubygems_version: 3.6.2
|
|
126
125
|
specification_version: 4
|
|
127
|
-
summary: Lightweight, no-nonsense, Shopify Admin API
|
|
128
|
-
retry
|
|
126
|
+
summary: Lightweight, no-nonsense, Shopify GraphQL Admin API client with built-in
|
|
127
|
+
pagination and retry
|
|
129
128
|
test_files: []
|