artemis 0.5.1 → 0.7.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/.github/workflows/ruby.yml +64 -0
- data/.gitignore +1 -0
- data/Appraisals +12 -20
- data/CHANGELOG.md +45 -0
- data/Gemfile +2 -0
- data/README.md +71 -6
- data/artemis.gemspec +0 -1
- data/gemfiles/rails_50.gemfile +3 -1
- data/gemfiles/rails_51.gemfile +3 -1
- data/gemfiles/rails_52.gemfile +3 -1
- data/gemfiles/rails_60.gemfile +3 -1
- data/gemfiles/{rails_40.gemfile → rails_61.gemfile} +5 -3
- data/gemfiles/{rails_41.gemfile → rails_70.gemfile} +5 -4
- data/gemfiles/rails_edge.gemfile +2 -0
- data/lib/artemis/adapters/abstract_adapter.rb +1 -1
- data/lib/artemis/adapters/curb_adapter.rb +17 -7
- data/lib/artemis/adapters/multi_domain_adapter.rb +58 -0
- data/lib/artemis/adapters/net_http_adapter.rb +25 -16
- data/lib/artemis/adapters/net_http_persistent_adapter.rb +7 -1
- data/lib/artemis/adapters/test_adapter.rb +22 -3
- data/lib/artemis/adapters.rb +1 -0
- data/lib/artemis/client.rb +42 -8
- data/lib/artemis/graphql_endpoint.rb +11 -5
- data/lib/artemis/railtie.rb +16 -8
- data/lib/artemis/test_helper.rb +2 -1
- data/lib/artemis/version.rb +1 -1
- data/lib/generators/artemis/mutation/templates/mutation.graphql +1 -1
- data/lib/generators/artemis/query/query_generator.rb +14 -2
- data/lib/generators/artemis/query/templates/fixture.yml +19 -0
- data/lib/generators/artemis/query/templates/query.graphql +2 -2
- data/spec/adapters_spec.rb +165 -10
- data/spec/autoloading_spec.rb +4 -4
- data/spec/client_spec.rb +38 -2
- data/spec/fixtures/metaphysics/{_artist_fragment.graphql → _artist_fields.graphql} +0 -0
- data/spec/fixtures/metaphysics/artists.graphql +1 -1
- data/spec/fixtures/responses/{spotify → spotify_client}/artist.yml +0 -0
- data/spec/test_helper_spec.rb +10 -1
- metadata +13 -26
- data/.travis.yml +0 -69
- data/gemfiles/rails_42.gemfile +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b64a8fd49d4d32ab4fd0dbda0f20005b68129fc1eee01de0f525424a19d1d28
|
4
|
+
data.tar.gz: eae9f56e2f7bbd832278cf1546c931824ea5f7bfa969e28cdf9dbe2e8a6e4ab6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 061e522011314b8f3a712a1a13c504653e7b7979e17ff239298d98742f08ae3fea14cd9772970dd72dd1c9e361572d6c70b076f3b0e4ee552f9d1fc1e2a7e69d
|
7
|
+
data.tar.gz: 2d1fec853399e9ec52b74e3c5c7eae407a9affe39222f7719d993f098ef839cd2da72dfbb353f967c025c2d72b464dbdc3f56dadfa4e596b2d9ea32c43d6119f
|
@@ -0,0 +1,64 @@
|
|
1
|
+
name: build
|
2
|
+
|
3
|
+
on:
|
4
|
+
- push
|
5
|
+
- pull_request
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
ruby_version:
|
12
|
+
- '3.1'
|
13
|
+
- '3.0'
|
14
|
+
- '2.7'
|
15
|
+
- '2.6'
|
16
|
+
# - 'jruby-9.2.17.0'
|
17
|
+
gemfile:
|
18
|
+
- gemfiles/rails_70.gemfile
|
19
|
+
- gemfiles/rails_61.gemfile
|
20
|
+
- gemfiles/rails_60.gemfile
|
21
|
+
- gemfiles/rails_52.gemfile
|
22
|
+
- gemfiles/rails_51.gemfile
|
23
|
+
- gemfiles/rails_50.gemfile
|
24
|
+
# - gemfiles/rails_edge.gemfile
|
25
|
+
exclude:
|
26
|
+
- ruby_version: '3.1'
|
27
|
+
gemfile: gemfiles/rails_61.gemfile
|
28
|
+
- ruby_version: '3.1'
|
29
|
+
gemfile: gemfiles/rails_60.gemfile
|
30
|
+
- ruby_version: '3.1'
|
31
|
+
gemfile: gemfiles/rails_52.gemfile
|
32
|
+
- ruby_version: '3.1'
|
33
|
+
gemfile: gemfiles/rails_51.gemfile
|
34
|
+
- ruby_version: '3.1'
|
35
|
+
gemfile: gemfiles/rails_50.gemfile
|
36
|
+
- ruby_version: '3.0'
|
37
|
+
gemfile: gemfiles/rails_52.gemfile
|
38
|
+
- ruby_version: '3.0'
|
39
|
+
gemfile: gemfiles/rails_51.gemfile
|
40
|
+
- ruby_version: '3.0'
|
41
|
+
gemfile: gemfiles/rails_50.gemfile
|
42
|
+
- ruby_version: '2.7'
|
43
|
+
gemfile: gemfiles/rails_52.gemfile
|
44
|
+
- ruby_version: '2.7'
|
45
|
+
gemfile: gemfiles/rails_51.gemfile
|
46
|
+
- ruby_version: '2.7'
|
47
|
+
gemfile: gemfiles/rails_50.gemfile
|
48
|
+
- ruby_version: '2.6'
|
49
|
+
gemfile: gemfiles/rails_70.gemfile
|
50
|
+
# - ruby_version: '2.6'
|
51
|
+
# gemfile: gemfiles/rails_edge.gemfile
|
52
|
+
runs-on: ubuntu-18.04
|
53
|
+
env:
|
54
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
55
|
+
steps:
|
56
|
+
- uses: actions/checkout@v2
|
57
|
+
- name: Install curl
|
58
|
+
run: sudo apt-get install curl libcurl4-openssl-dev
|
59
|
+
- name: Set up Ruby
|
60
|
+
uses: ruby/setup-ruby@v1
|
61
|
+
with:
|
62
|
+
ruby-version: ${{ matrix.ruby_version }}
|
63
|
+
bundler-cache: true
|
64
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
data/Appraisals
CHANGED
@@ -6,6 +6,18 @@ appraise "rails_edge" do
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
+
appraise "rails_70" do
|
10
|
+
gem "rails", '~> 7.0.0'
|
11
|
+
gem "railties", '~> 7.0.0'
|
12
|
+
gem "activesupport", '~> 7.0.0'
|
13
|
+
end
|
14
|
+
|
15
|
+
appraise "rails_61" do
|
16
|
+
gem "rails", '~> 6.1.0'
|
17
|
+
gem "railties", '~> 6.1.0'
|
18
|
+
gem "activesupport", '~> 6.1.0'
|
19
|
+
end
|
20
|
+
|
9
21
|
appraise "rails_60" do
|
10
22
|
gem "rails", '~> 6.0.0.rc1'
|
11
23
|
gem "railties", '~> 6.0.0.rc1'
|
@@ -30,23 +42,3 @@ appraise "rails_50" do
|
|
30
42
|
gem "activesupport", '~> 5.0.0'
|
31
43
|
gem "minitest", '5.10.3'
|
32
44
|
end
|
33
|
-
|
34
|
-
appraise "rails_42" do
|
35
|
-
gem "rails", '~> 4.2.0'
|
36
|
-
gem "railties", '~> 4.2.0'
|
37
|
-
gem "activesupport", '~> 4.2.0'
|
38
|
-
gem "minitest", '5.10.3'
|
39
|
-
end
|
40
|
-
|
41
|
-
appraise "rails_41" do
|
42
|
-
gem "rails", '~> 4.1.0'
|
43
|
-
gem "railties", '~> 4.1.0'
|
44
|
-
gem "activesupport", '~> 4.1.0'
|
45
|
-
gem "minitest", '5.10.3'
|
46
|
-
end
|
47
|
-
|
48
|
-
appraise "rails_40" do
|
49
|
-
gem "rails", '~> 4.0.0'
|
50
|
-
gem "railties", '~> 4.0.0'
|
51
|
-
gem "activesupport", '~> 4.0.0'
|
52
|
-
end
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,48 @@
|
|
1
|
+
|
2
|
+
## v0.7.0
|
3
|
+
|
4
|
+
_<sup>unreleased</sup>_
|
5
|
+
|
6
|
+
#### Features
|
7
|
+
|
8
|
+
- Add support for Ruby 3.1 and Rails 7.0
|
9
|
+
- Add support for [the Multiplex query](https://graphql-ruby.org/queries/multiplex.html)
|
10
|
+
- Do not allow the usage of the `multi_domain` adapter to be nested ([<tt>9b7b520</tt>](https://github.com/yuki24/artemis/commit/9b7b5202c9fbe424d4ca22f05dc9c9759b5202c3))
|
11
|
+
- Do not require fragment files to end with `_fragment.graphql` ([<tt>3c6c0fa</tt>](https://github.com/yuki24/artemis/commit/3c6c0fa))
|
12
|
+
- Allow for overriding the namespace used for resolving graphql file paths ([<tt>bd18762</tt>](https://github.com/yuki24/artemis/commit/bd18762))
|
13
|
+
|
14
|
+
## [v0.6.0](https://github.com/yuki24/artemis/tree/v0.6.0)
|
15
|
+
|
16
|
+
_<sup>released at 2021-09-03 04:17:55 UTC</sup>_
|
17
|
+
|
18
|
+
#### Features
|
19
|
+
|
20
|
+
- Add support for Ruby 3.0 and Rails 6.0, 6.1
|
21
|
+
- Add the multi domain adapter ([<tt>744b8ea</tt>](https://github.com/yuki24/artemis/commit/744b8ea35795b4e6cc4fdc1ebb63dd9a4e9819f0))
|
22
|
+
|
23
|
+
#### Fixes
|
24
|
+
|
25
|
+
- ~~Generate fixture YAML files on `rails g artemis:query queryName` ([#78](https://github.com/yuki24/artemis/pull/78))~~ Removed due to a bug for now.
|
26
|
+
- Address warnings from Ruby 2.7 ([<tt>408adcb</tt>](https://github.com/yuki24/artemis/commit/408adcb3f39912f7afb7b3690a52f1d593662b7b))
|
27
|
+
- Avoid crashing when config/graphql.yml does not exist ([@dlackty](https://github.com/dlackty), [#76](https://github.com/yuki24/artemis/pull/76))
|
28
|
+
|
29
|
+
## [v0.5.2](https://github.com/yuki24/artemis/tree/v0.5.2)
|
30
|
+
|
31
|
+
_<sup>released at 2019-07-26 03:21:43 UTC</sup>_
|
32
|
+
|
33
|
+
#### Fixes
|
34
|
+
|
35
|
+
- Fixes an issue where fixtures can not be looked up properly when the client has two or more words in its name ([@JanStevens](https://github.com/JanStevens), issue: [#72](https://github.com/yuki24/artemis/issues/72), PR: [#73](https://github.com/yuki24/artemis/pull/73))
|
36
|
+
|
37
|
+
## [v0.5.1](https://github.com/yuki24/artemis/tree/v0.5.1)
|
38
|
+
|
39
|
+
_<sup>released at 2019-07-01 14:25:35 UTC</sup>_
|
40
|
+
|
41
|
+
#### Fixes
|
42
|
+
|
43
|
+
- Fixes an issue where callbacks are shared across all clients ([@JanStevens](https://github.com/JanStevens), issue: [#69](https://github.com/yuki24/artemis/issues/69), PR: [#70](https://github.com/yuki24/artemis/pull/70))
|
44
|
+
- Fixes an issue where fixtures with the same name cause a conflict ([@JanStevens](https://github.com/JanStevens), Issue: [#68](https://github.com/yuki24/artemis/issues/68), commit: [<tt>e1f57f4</tt>](https://github.com/yuki24/artemis/commit/e1f57f49ebb032553d7a6f70e48422fc9825c119))
|
45
|
+
|
1
46
|
## [v0.5.0](https://github.com/yuki24/artemis/tree/v0.5.0)
|
2
47
|
|
3
48
|
_<sup>released at 2019-06-02 22:01:57 UTC</sup>_
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Artemis [](https://github.com/yuki24/artemis/actions/workflows/ruby.yml) [](https://rubygems.org/gems/artemis)
|
2
2
|
|
3
3
|
Artemis is a GraphQL client that is designed to fit well on Rails.
|
4
4
|
|
@@ -51,7 +51,7 @@ query($id: String!) {
|
|
51
51
|
}
|
52
52
|
```
|
53
53
|
|
54
|
-
Then you could the class method that has the matching name `artist`:
|
54
|
+
Then you could call the class method that has the matching name `artist`:
|
55
55
|
|
56
56
|
```ruby
|
57
57
|
Artsy.artist(id: "pablo-picasso")
|
@@ -92,9 +92,35 @@ Artemis assumes that the files related to GraphQL are organized in a certain way
|
|
92
92
|
└──vendor/graphql/schema/artsy.json
|
93
93
|
```
|
94
94
|
|
95
|
+
### Fragments
|
96
|
+
Fragments are defined in defined in a standard way in a file named `_artwork_fragment.graphql` with the standard convention:
|
97
|
+
|
98
|
+
```graphql
|
99
|
+
fragment on Artwork {
|
100
|
+
id,
|
101
|
+
name,
|
102
|
+
artist_id
|
103
|
+
# other artwork fields here
|
104
|
+
}
|
105
|
+
```
|
106
|
+
|
107
|
+
The way of calling an Artemis fragment on other queries or models is with a **Rails convention**. Let us suppose we have the Artist model and its corresponding artwork. The way of nesting or calling the artwork on the artist model would look like this:
|
108
|
+
|
109
|
+
```graphql
|
110
|
+
fragment on Artist {
|
111
|
+
id,
|
112
|
+
name,
|
113
|
+
artworks {
|
114
|
+
...Artsy::ArtworkFragment
|
115
|
+
}
|
116
|
+
}
|
117
|
+
```
|
118
|
+
|
119
|
+
Where `Artsy` is the name of the folder/module.
|
120
|
+
|
95
121
|
## Callbacks
|
96
122
|
|
97
|
-
|
123
|
+
You can use the `before_execute` callback to intercept outgoing requests and the `after_execute` callback to observe the
|
98
124
|
response. A common operation that's done in the `before_execute` hook is assigning a token to the header:
|
99
125
|
|
100
126
|
```ruby
|
@@ -121,6 +147,44 @@ class Artsy < Artemis::Client
|
|
121
147
|
end
|
122
148
|
```
|
123
149
|
|
150
|
+
## Multi domain support
|
151
|
+
|
152
|
+
Services like Shopify provide
|
153
|
+
[a different endpoint per customer](https://shopify.dev/api/admin/graphql/reference#graphql-endpoint) (e.g.
|
154
|
+
`https://{shop}.myshopify.com`). In order to switch the endpoint on a per-request basis, you will have to use the
|
155
|
+
`:multi_domain` adapter. This is a wrapper adapter that relies on an actual HTTP adapter such as `:net_http` and
|
156
|
+
`:curb` so that e.g. it can maintain multiple connections for each endpoint if necessary. This could be configured
|
157
|
+
as shown below:
|
158
|
+
|
159
|
+
```yaml
|
160
|
+
default: &default
|
161
|
+
# Specify the :multi_domain adapter:
|
162
|
+
adapter: :multi_domain
|
163
|
+
|
164
|
+
# Other configurations such as `timeout` and `pool_size` are passed down to the underlying adapter:
|
165
|
+
timeout: 10
|
166
|
+
pool_size: 25
|
167
|
+
|
168
|
+
# Additional adapter-specific configurations could be configured as `adapter_options`:
|
169
|
+
adapter_options:
|
170
|
+
# Here you can configure the actual adapter to use. By default, it is set to :net_http. Available adapters are
|
171
|
+
# :net_http, :net_http_persistent, :curb, and :test. You can not nest the use of the `:multi_domain` adapter.
|
172
|
+
adapter: :net_http
|
173
|
+
|
174
|
+
development:
|
175
|
+
shopify:
|
176
|
+
<<: *default
|
177
|
+
|
178
|
+
...
|
179
|
+
```
|
180
|
+
|
181
|
+
Upon making a request you will also have to specify the `url` option:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
# Makes a request to https://myawesomeshop.myshopify.com:
|
185
|
+
Shopify.with_context(url: "https://myawesomeshop.myshopify.com").product(id: "...")
|
186
|
+
```
|
187
|
+
|
124
188
|
## Configuration
|
125
189
|
|
126
190
|
You can configure the GraphQL client using the following options. Those configurations are found in the
|
@@ -143,9 +207,10 @@ There are four adapter options available. Choose the adapter that best fits on y
|
|
143
207
|
| `:curb` | HTTP/1.1, **HTTP/2** | **Yes** | **Fastest** | [`curb 0.9.6+`][curb]<br>[`libcurl 7.64.0+`][curl]<br>[`nghttp2 1.0.0+`][nghttp]
|
144
208
|
| `:net_http` (default) | HTTP/1.1 only | No | Slow | **None**
|
145
209
|
| `:net_http_persistent` | HTTP/1.1 only | **Yes** | **Fast** | [`net-http-persistent 3.0.0+`][nhp]
|
146
|
-
| `:
|
210
|
+
| `:multi_domain` | See [multi domain support](#multi-domain-support)
|
211
|
+
| `:test` | See [Testing](#testing)
|
147
212
|
|
148
|
-
|
213
|
+
#### Third-party adapters
|
149
214
|
|
150
215
|
This is a comminuty-maintained adapter. Want to add yours? Send us a pull request!
|
151
216
|
|
@@ -153,7 +218,7 @@ This is a comminuty-maintained adapter. Want to add yours? Send us a pull reques
|
|
153
218
|
| ---------------------- | ------------|
|
154
219
|
| [`:net_http_hmac`](https://github.com/JanStevens/artemis-api-auth/tree/master) | provides a new Adapter for the Artemis GraphQL ruby client to support HMAC Authentication using [ApiAuth](https://github.com/mgomes/api_auth). |
|
155
220
|
|
156
|
-
|
221
|
+
#### Writing your own adapter
|
157
222
|
|
158
223
|
When the built-in adapters do not satisfy your needs, you may want to implement your own adapter. You could do so by following the steps below. Let's implement the [`:net_http_hmac`](https://github.com/JanStevens/artemis-api-auth/tree/master) adapter as an example.
|
159
224
|
|
data/artemis.gemspec
CHANGED
@@ -22,7 +22,6 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency "appraisal", ">= 2.2"
|
24
24
|
spec.add_development_dependency "bundler", ">= 1.16"
|
25
|
-
spec.add_development_dependency "curb", ">= 0.9.6"
|
26
25
|
spec.add_development_dependency "net-http-persistent", ">= 3.0"
|
27
26
|
spec.add_development_dependency "rake", ">= 10.0"
|
28
27
|
spec.add_development_dependency "rspec", ">= 3.8"
|
data/gemfiles/rails_50.gemfile
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "~> 5.0.0"
|
6
5
|
gem "pry"
|
7
6
|
gem "pry-byebug", platforms: :mri
|
7
|
+
gem "curb", ">= 0.9.6"
|
8
|
+
gem "webrick"
|
9
|
+
gem "rails", "~> 5.0.0"
|
8
10
|
gem "railties", "~> 5.0.0"
|
9
11
|
gem "activesupport", "~> 5.0.0"
|
10
12
|
gem "minitest", "5.10.3"
|
data/gemfiles/rails_51.gemfile
CHANGED
data/gemfiles/rails_52.gemfile
CHANGED
data/gemfiles/rails_60.gemfile
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "~> 6.0.0.rc1"
|
6
5
|
gem "pry"
|
7
6
|
gem "pry-byebug", platforms: :mri
|
7
|
+
gem "curb", ">= 0.9.6"
|
8
|
+
gem "webrick"
|
9
|
+
gem "rails", "~> 6.0.0.rc1"
|
8
10
|
gem "railties", "~> 6.0.0.rc1"
|
9
11
|
gem "activesupport", "~> 6.0.0.rc1"
|
10
12
|
|
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "~> 4.0.0"
|
6
5
|
gem "pry"
|
7
6
|
gem "pry-byebug", platforms: :mri
|
8
|
-
gem "
|
9
|
-
gem "
|
7
|
+
gem "curb", ">= 0.9.6"
|
8
|
+
gem "webrick"
|
9
|
+
gem "rails", "~> 6.1.0"
|
10
|
+
gem "railties", "~> 6.1.0"
|
11
|
+
gem "activesupport", "~> 6.1.0"
|
10
12
|
|
11
13
|
gemspec path: "../"
|
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "rails", "~> 4.1.0"
|
6
5
|
gem "pry"
|
7
6
|
gem "pry-byebug", platforms: :mri
|
8
|
-
gem "
|
9
|
-
gem "
|
10
|
-
gem "
|
7
|
+
gem "curb", ">= 0.9.6"
|
8
|
+
gem "webrick"
|
9
|
+
gem "rails", "~> 7.0.0"
|
10
|
+
gem "railties", "~> 7.0.0"
|
11
|
+
gem "activesupport", "~> 7.0.0"
|
11
12
|
|
12
13
|
gemspec path: "../"
|
data/gemfiles/rails_edge.gemfile
CHANGED
@@ -15,7 +15,7 @@ module Artemis
|
|
15
15
|
"Content-Type" => "application/json"
|
16
16
|
}.freeze
|
17
17
|
|
18
|
-
def initialize(uri, service_name: , timeout: , pool_size: )
|
18
|
+
def initialize(uri, service_name: , timeout: , pool_size: , adapter_options: {})
|
19
19
|
raise ArgumentError, "url is required (given `#{uri.inspect}')" if uri.blank?
|
20
20
|
|
21
21
|
super(uri) # Do not pass in the block to avoid getting #headers and #connection overridden.
|
@@ -13,25 +13,35 @@ module Artemis
|
|
13
13
|
class CurbAdapter < AbstractAdapter
|
14
14
|
attr_reader :multi
|
15
15
|
|
16
|
-
def initialize(uri, service_name: , timeout: , pool_size: )
|
16
|
+
def initialize(uri, service_name: , timeout: , pool_size: , adapter_options: {})
|
17
17
|
super
|
18
18
|
|
19
19
|
@multi = Curl::Multi.new
|
20
20
|
@multi.pipeline = Curl::CURLPIPE_MULTIPLEX if defined?(Curl::CURLPIPE_MULTIPLEX)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
23
|
+
def multiplex(queries, context: {})
|
24
|
+
make_request({ _json: queries }, context)
|
25
|
+
end
|
25
26
|
|
27
|
+
def execute(document:, operation_name: nil, variables: {}, context: {})
|
26
28
|
body = {}
|
27
29
|
body["query"] = document.to_query_string
|
28
30
|
body["variables"] = variables if variables.any?
|
29
31
|
body["operationName"] = operation_name if operation_name
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
make_request(body, context)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def make_request(body, context)
|
39
|
+
easy = Curl::Easy.new(uri.to_s)
|
40
|
+
|
41
|
+
easy.timeout = timeout
|
42
|
+
easy.multi = multi
|
43
|
+
easy.headers = DEFAULT_HEADERS.merge(headers(context))
|
44
|
+
easy.post_body = JSON.generate(body)
|
35
45
|
|
36
46
|
if defined?(Curl::CURLPIPE_MULTIPLEX)
|
37
47
|
# This ensures libcurl waits for the connection to reveal if it is
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'artemis/adapters/abstract_adapter'
|
4
|
+
|
5
|
+
module Artemis
|
6
|
+
module Adapters
|
7
|
+
class MultiDomainAdapter < AbstractAdapter
|
8
|
+
attr_reader :adapter
|
9
|
+
|
10
|
+
def initialize(_uri, service_name: , timeout: , pool_size: , adapter_options: {})
|
11
|
+
if adapter_options[:adapter] == :multi_domain
|
12
|
+
raise ArgumentError, "You can not use the :multi_domain adapter with the :multi_domain adapter."
|
13
|
+
end
|
14
|
+
|
15
|
+
@connection_by_url = {}
|
16
|
+
@service_name = service_name.to_s
|
17
|
+
@timeout = timeout
|
18
|
+
@pool_size = pool_size
|
19
|
+
@adapter = adapter_options[:adapter] || :net_http
|
20
|
+
@mutex_for_connection = Mutex.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def multiplex(queries, context: {})
|
24
|
+
url = context[:url]
|
25
|
+
|
26
|
+
if url.nil?
|
27
|
+
raise ArgumentError, 'The MultiDomain adapter requires a url on every request. Please specify a url with a context: ' \
|
28
|
+
'Client.multiplex(url: "https://awesomeshop.domain.conm") { ... }'
|
29
|
+
end
|
30
|
+
|
31
|
+
connection_for_url(url).multiplex(queries, context: context)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Makes an HTTP request for GraphQL query.
|
35
|
+
def execute(document:, operation_name: nil, variables: {}, context: {})
|
36
|
+
url = context[:url]
|
37
|
+
|
38
|
+
if url.nil?
|
39
|
+
raise ArgumentError, 'The MultiDomain adapter requires a url on every request. Please specify a url with a context: ' \
|
40
|
+
'Client.with_context(url: "https://awesomeshop.domain.conm")'
|
41
|
+
end
|
42
|
+
|
43
|
+
connection_for_url(url).execute(document: document, operation_name: operation_name, variables: variables, context: context)
|
44
|
+
end
|
45
|
+
|
46
|
+
def connection
|
47
|
+
raise NotImplementedError, "Calling the #connection method without a URI is not supported. Please use the " \
|
48
|
+
"#connection_for_url(uri) instead."
|
49
|
+
end
|
50
|
+
|
51
|
+
def connection_for_url(url)
|
52
|
+
@connection_by_url[url.to_s] || @mutex_for_connection.synchronize do
|
53
|
+
@connection_by_url[url.to_s] ||= ::Artemis::Adapters.lookup(adapter).new(url, service_name: service_name, timeout: timeout, pool_size: pool_size)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -9,20 +9,39 @@ require 'artemis/exceptions'
|
|
9
9
|
module Artemis
|
10
10
|
module Adapters
|
11
11
|
class NetHttpAdapter < AbstractAdapter
|
12
|
+
def multiplex(queries, context: {})
|
13
|
+
make_request({ _json: queries }, context)
|
14
|
+
end
|
15
|
+
|
12
16
|
# Makes an HTTP request for GraphQL query.
|
13
17
|
def execute(document:, operation_name: nil, variables: {}, context: {})
|
14
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
15
|
-
|
16
|
-
request.basic_auth(uri.user, uri.password) if uri.user || uri.password
|
17
|
-
|
18
|
-
DEFAULT_HEADERS.merge(headers(context)).each { |name, value| request[name] = value }
|
19
|
-
|
20
18
|
body = {}
|
21
19
|
body["query"] = document.to_query_string
|
22
20
|
body["variables"] = variables if variables.any?
|
23
21
|
body["operationName"] = operation_name if operation_name
|
22
|
+
|
23
|
+
make_request(body, context)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a fresh Net::HTTP object that creates a new connection.
|
27
|
+
def connection
|
28
|
+
Net::HTTP.new(uri.host, uri.port).tap do |client|
|
29
|
+
client.use_ssl = uri.scheme == "https"
|
30
|
+
client.open_timeout = timeout
|
31
|
+
client.read_timeout = timeout
|
32
|
+
client.write_timeout = timeout if client.respond_to?(:write_timeout=)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def make_request(body, context)
|
39
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
40
|
+
request.basic_auth(uri.user, uri.password) if uri.user || uri.password
|
24
41
|
request.body = JSON.generate(body)
|
25
42
|
|
43
|
+
DEFAULT_HEADERS.merge(headers(context)).each { |name, value| request[name] = value }
|
44
|
+
|
26
45
|
response = connection.request(request)
|
27
46
|
|
28
47
|
case response.code.to_i
|
@@ -34,16 +53,6 @@ module Artemis
|
|
34
53
|
{ "errors" => [{ "message" => "#{response.code} #{response.message}" }] }
|
35
54
|
end
|
36
55
|
end
|
37
|
-
|
38
|
-
# Returns a fresh Net::HTTP object that creates a new connection.
|
39
|
-
def connection
|
40
|
-
Net::HTTP.new(uri.host, uri.port).tap do |client|
|
41
|
-
client.use_ssl = uri.scheme == "https"
|
42
|
-
client.open_timeout = timeout
|
43
|
-
client.read_timeout = timeout
|
44
|
-
client.write_timeout = timeout if client.respond_to?(:write_timeout=)
|
45
|
-
end
|
46
|
-
end
|
47
56
|
end
|
48
57
|
end
|
49
58
|
end
|
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'delegate'
|
4
4
|
|
5
|
+
begin
|
6
|
+
require "active_support/isolated_execution_state"
|
7
|
+
rescue LoadError
|
8
|
+
# no-op... Rails 7.0 requires this.
|
9
|
+
end
|
10
|
+
|
5
11
|
require 'active_support/core_ext/numeric/time'
|
6
12
|
require 'net/http/persistent'
|
7
13
|
|
@@ -12,7 +18,7 @@ module Artemis
|
|
12
18
|
class NetHttpPersistentAdapter < NetHttpAdapter
|
13
19
|
attr_reader :_connection, :raw_connection
|
14
20
|
|
15
|
-
def initialize(uri, service_name: , timeout: , pool_size: )
|
21
|
+
def initialize(uri, service_name: , timeout: , pool_size: , adapter_options: {})
|
16
22
|
super
|
17
23
|
|
18
24
|
@raw_connection = Net::HTTP::Persistent.new(name: service_name, pool_size: pool_size)
|
@@ -12,20 +12,39 @@ module Artemis
|
|
12
12
|
self.responses = []
|
13
13
|
|
14
14
|
Request = Struct.new(:document, :operation_name, :variables, :context)
|
15
|
+
Multiplex = Struct.new(:queries, :context)
|
15
16
|
|
16
|
-
private_constant :Request
|
17
|
+
private_constant :Request, :Multiplex
|
17
18
|
|
18
19
|
def initialize(*)
|
19
20
|
end
|
20
21
|
|
22
|
+
def multiplex(queries, context: {})
|
23
|
+
self.requests << Multiplex.new(queries, context)
|
24
|
+
|
25
|
+
queries.map do |query|
|
26
|
+
result = responses.detect do |mock|
|
27
|
+
query[:operationName] == mock.operation_name && (mock.arguments == :__unspecified__ || query[:variables] == mock.arguments)
|
28
|
+
end
|
29
|
+
|
30
|
+
result&.data || fake_response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
21
34
|
def execute(**arguments)
|
22
35
|
self.requests << Request.new(*arguments.values_at(:document, :operation_name, :variables, :context))
|
23
36
|
|
24
37
|
response = responses.detect do |mock|
|
25
|
-
arguments[:operation_name] == mock.operation_name && mock.arguments == :__unspecified__ || arguments[:variables] == mock.arguments
|
38
|
+
arguments[:operation_name] == mock.operation_name && (mock.arguments == :__unspecified__ || arguments[:variables] == mock.arguments)
|
26
39
|
end
|
27
40
|
|
28
|
-
response&.data ||
|
41
|
+
response&.data || fake_response
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def fake_response
|
47
|
+
{
|
29
48
|
'data' => { 'test' => 'data' },
|
30
49
|
'errors' => [],
|
31
50
|
'extensions' => {}
|