graphql_connector 1.1.0 → 1.3.1
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/ci.yaml +37 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile.lock +29 -29
- data/README.md +55 -9
- data/examples/departments_service_class_examples.rb +13 -0
- data/examples/mutation_examples.rb +17 -0
- data/examples/query_examples.rb +5 -0
- data/examples/raw_query_examples.rb +5 -0
- data/graphql_connector.gemspec +1 -2
- data/lib/graphql_connector.rb +3 -1
- data/lib/graphql_connector/base_server_type.rb +14 -22
- data/lib/graphql_connector/configuration.rb +3 -2
- data/lib/graphql_connector/formatters/base_format.rb +81 -0
- data/lib/graphql_connector/formatters/mutation_format.rb +14 -0
- data/lib/graphql_connector/formatters/query_format.rb +14 -0
- data/lib/graphql_connector/http_client.rb +25 -8
- data/lib/graphql_connector/service_classable/class_method_validator.rb +2 -2
- data/lib/graphql_connector/service_classable/queryable.rb +32 -0
- data/lib/graphql_connector/version.rb +1 -1
- metadata +13 -24
- data/.travis.yml +0 -10
- data/lib/graphql_connector/query_builder.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b8c2af2590f1daf462e0f348e64078c530a4c7f6833a7d8692e6bada0f11291
|
4
|
+
data.tar.gz: 52edb3725223b2538f91b1904fa57a071ab0b43b853f37f23242e1dbb8d7eb50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c82b787552cf4590bae68e4eb15103252a47660ba4a8b2d7645deb9e218034cadbca24feaf9ef610818106e322fc7916a91fdd3726d251e49c0051224666d3c2
|
7
|
+
data.tar.gz: 491988a32bc66f1d597d32dbf0164b5f5a23a87923ac6d4da3c0fbc8272de1b6721ba8657b35e99ad221a9bcb2860431964e22281fcba341da36f3f5dd49ba1e
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: ['2.4.10', '2.5.9', '2.6.7', '2.7.3', '3.0.1']
|
11
|
+
name: "ruby ${{ matrix.ruby }}"
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v1
|
14
|
+
- uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: ${{ matrix.ruby }}
|
17
|
+
- name: Install dependencies
|
18
|
+
run: |
|
19
|
+
gem install bundler
|
20
|
+
bundle install
|
21
|
+
- name: Run Test with rspec
|
22
|
+
run: bundle exec rspec spec
|
23
|
+
rubocop:
|
24
|
+
name: Rubocop
|
25
|
+
runs-on: ubuntu-latest
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v2
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: 2.7.3
|
31
|
+
- name: Install dependencies
|
32
|
+
run: |
|
33
|
+
gem install bundler
|
34
|
+
bundle install
|
35
|
+
- name: Build and test
|
36
|
+
run: |
|
37
|
+
bundle exec rubocop
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## 1.3.1 (2021-06-04)
|
2
|
+
|
3
|
+
* add more specs to test headers and connectors
|
4
|
+
* make the headers option optinal
|
5
|
+
* update the readme to explain the connector functionality better
|
6
|
+
|
7
|
+
## 1.3.0 (2021-06-02)
|
8
|
+
|
9
|
+
* add the option to use a connector instead of init header for authorization
|
10
|
+
part of headers
|
11
|
+
|
12
|
+
## 1.2.1 (2021-05-25)
|
13
|
+
|
14
|
+
* relax httparty dependency(`~> 0.17` => `~> 0.16`)
|
15
|
+
|
16
|
+
## 1.2.0 (2020-12-22)
|
17
|
+
|
18
|
+
### Features
|
19
|
+
* Add `mutation` under server namespace and service class inclusion
|
20
|
+
* See `README` for details
|
21
|
+
|
22
|
+
## 1.1.1 (2020-5-04)
|
23
|
+
|
24
|
+
### BugFix
|
25
|
+
* Omit invalid `()` for empty conditions in `query` method
|
26
|
+
|
1
27
|
## 1.1.0 (2020-4-19)
|
2
28
|
|
3
29
|
### Features
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
graphql_connector (1.
|
5
|
-
httparty (~> 0.
|
4
|
+
graphql_connector (1.3.0)
|
5
|
+
httparty (~> 0.16)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -10,45 +10,46 @@ GEM
|
|
10
10
|
ast (2.4.0)
|
11
11
|
coderay (1.1.2)
|
12
12
|
diff-lcs (1.3)
|
13
|
-
httparty (0.
|
13
|
+
httparty (0.18.1)
|
14
14
|
mime-types (~> 3.0)
|
15
15
|
multi_xml (>= 0.5.2)
|
16
|
-
jaro_winkler (1.5.
|
17
|
-
method_source (0.
|
16
|
+
jaro_winkler (1.5.4)
|
17
|
+
method_source (1.0.0)
|
18
18
|
mime-types (3.3.1)
|
19
19
|
mime-types-data (~> 3.2015)
|
20
|
-
mime-types-data (3.
|
20
|
+
mime-types-data (3.2021.0225)
|
21
21
|
multi_xml (0.6.0)
|
22
|
-
parallel (1.
|
23
|
-
parser (2.
|
22
|
+
parallel (1.19.1)
|
23
|
+
parser (2.7.1.1)
|
24
24
|
ast (~> 2.4.0)
|
25
|
-
pry (0.
|
26
|
-
coderay (~> 1.1
|
27
|
-
method_source (~>
|
25
|
+
pry (0.13.1)
|
26
|
+
coderay (~> 1.1)
|
27
|
+
method_source (~> 1.0)
|
28
28
|
rainbow (3.0.0)
|
29
|
-
|
30
|
-
rspec (3.
|
31
|
-
rspec-core (~> 3.
|
32
|
-
rspec-expectations (~> 3.
|
33
|
-
rspec-mocks (~> 3.
|
34
|
-
rspec-core (3.
|
35
|
-
rspec-support (~> 3.
|
36
|
-
rspec-expectations (3.
|
29
|
+
rexml (3.2.5)
|
30
|
+
rspec (3.9.0)
|
31
|
+
rspec-core (~> 3.9.0)
|
32
|
+
rspec-expectations (~> 3.9.0)
|
33
|
+
rspec-mocks (~> 3.9.0)
|
34
|
+
rspec-core (3.9.1)
|
35
|
+
rspec-support (~> 3.9.1)
|
36
|
+
rspec-expectations (3.9.1)
|
37
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
-
rspec-support (~> 3.
|
39
|
-
rspec-mocks (3.
|
38
|
+
rspec-support (~> 3.9.0)
|
39
|
+
rspec-mocks (3.9.1)
|
40
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
-
rspec-support (~> 3.
|
42
|
-
rspec-support (3.
|
43
|
-
rubocop (0.
|
41
|
+
rspec-support (~> 3.9.0)
|
42
|
+
rspec-support (3.9.2)
|
43
|
+
rubocop (0.82.0)
|
44
44
|
jaro_winkler (~> 1.5.1)
|
45
45
|
parallel (~> 1.10)
|
46
|
-
parser (>= 2.
|
46
|
+
parser (>= 2.7.0.1)
|
47
47
|
rainbow (>= 2.2.2, < 4.0)
|
48
|
+
rexml
|
48
49
|
ruby-progressbar (~> 1.7)
|
49
|
-
unicode-display_width (>= 1.4.0, <
|
50
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
50
51
|
ruby-progressbar (1.10.1)
|
51
|
-
unicode-display_width (1.
|
52
|
+
unicode-display_width (1.7.0)
|
52
53
|
|
53
54
|
PLATFORMS
|
54
55
|
ruby
|
@@ -57,9 +58,8 @@ DEPENDENCIES
|
|
57
58
|
bundler (~> 2.0)
|
58
59
|
graphql_connector!
|
59
60
|
pry (~> 0.10)
|
60
|
-
rake (~> 10.0)
|
61
61
|
rspec (~> 3.8)
|
62
62
|
rubocop (~> 0.75)
|
63
63
|
|
64
64
|
BUNDLED WITH
|
65
|
-
2.1.
|
65
|
+
2.1.4
|
data/README.md
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
|
4
4
|
[](https://badge.fury.io/rb/graphql_connector)
|
6
|
-
[](https://travis-ci.org/Garllon/graphql_connector)
|
6
|
+
[](https://github.com/Garllon/graphql_connector/actions?query=workflow%3ACI)
|
8
7
|
[](https://codeclimate.com/github/Garllon/graphql_connector/maintainability)
|
9
8
|
|
10
9
|
An easy connector to call your `graphql` server. Currently there is no schema
|
@@ -31,10 +30,31 @@ Or install it yourself as:
|
|
31
30
|
You need to configure the `graphql_connector` first:
|
32
31
|
``` ruby
|
33
32
|
GraphqlConnector.configure do |config|
|
34
|
-
config.add_server(name: 'Foo', uri: 'http://foo.com/api/graphql', headers: {})
|
33
|
+
config.add_server(name: 'Foo', uri: 'http://foo.com/api/graphql', headers: {}, connector: {})
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
The connector is expecting that it contains a `base` connector instance and a
|
38
|
+
`method` parameter as string, where it gets the token. WE expect that the
|
39
|
+
method is a public method in your connector class. Currently like this:
|
40
|
+
```ruby
|
41
|
+
{ base: TokenAgent.new, method: 'get_authorization_header' }
|
42
|
+
```
|
43
|
+
|
44
|
+
Your method should return a hash like this:
|
45
|
+
```ruby
|
46
|
+
class TokenAgent
|
47
|
+
[...]
|
48
|
+
def get_authorization_header
|
49
|
+
[...]
|
50
|
+
{ 'Authorization' => 'Token HERE' }
|
51
|
+
end
|
35
52
|
end
|
36
53
|
```
|
37
54
|
|
55
|
+
When you set a connector, it will override the setting in the headers for
|
56
|
+
Authorization.
|
57
|
+
|
38
58
|
For each graphql server you wish to query use `add_server`.
|
39
59
|
|
40
60
|
Afterwards you will have the following options to fetch and/or mutate data with
|
@@ -42,6 +62,7 @@ one or many graphql servers:
|
|
42
62
|
|
43
63
|
* `raw_query` --> [Examples](examples/raw_query_examples.rb)
|
44
64
|
* `query` --> [Examples](examples/query_examples.rb)
|
65
|
+
* `mutation` --> [Examples](examples/mutation_examples.rb)
|
45
66
|
* `service class inclusion` --> [Examples](examples/departments_service_class_examples.rb)
|
46
67
|
|
47
68
|
See the following sub sections for details
|
@@ -92,18 +113,31 @@ Example:
|
|
92
113
|
|
93
114
|
---
|
94
115
|
|
116
|
+
### mutation
|
117
|
+
|
118
|
+
Works in the same way as [query](#query)
|
119
|
+
|
120
|
+
See also [here](examples/mutation_examples.rb) for example usage
|
121
|
+
|
95
122
|
### Service class inclusion
|
96
123
|
|
97
124
|
This approach can be used to `graphqlize` **any** kind of ruby (service) class
|
98
|
-
so that it has re-usable graphql query methods
|
125
|
+
so that it has re-usable graphql `query` and `mutation` **class methods**.
|
99
126
|
|
100
127
|
* First add `extend GraphqlConnector::<server>::Query` in the the class(es) that should be `graphqlized`
|
101
|
-
* Next for each mapping add a `add_query` or `add_raw_query` aliasing the graphql server type supports as follows:
|
102
|
-
* `add_query <alias>: <query type in graphql server>, params: [<any kind of query type params>], returns: [<selected_fields>]`
|
103
|
-
* `add_raw_query <alias>: <query string>, params: [<any kind of query type params>]`
|
104
|
-
* If <query type>/<query string> does not need them, omit `params`
|
105
128
|
|
106
|
-
|
129
|
+
* Then you can aliases as many graphql server types via `add_query` and/or `add_raw_query` and/or `add_mutation`:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
add_query <alias>: :<graphql_server_type>, params: [...], returns: [...]
|
133
|
+
|
134
|
+
add_raw_query <alias>: 'query { ... }', params: [...]
|
135
|
+
|
136
|
+
add_mutation <alias>: :<graphql_server_type>, params: [...], returns: [...]
|
137
|
+
```
|
138
|
+
* :grey_exclamation: If not needed omit `params`
|
139
|
+
|
140
|
+
See also [here](examples/departments_service_class_examples.rb) and also here for complete example usage:
|
107
141
|
|
108
142
|
```ruby
|
109
143
|
GraphqlConnector.configure do |config|
|
@@ -132,6 +166,10 @@ class Product
|
|
132
166
|
add_query by_category_id: :products,
|
133
167
|
params: :product_category,
|
134
168
|
returns: [product_category: [:id, :name]]
|
169
|
+
|
170
|
+
add_mutation create: :createProduct,
|
171
|
+
params: [:name, :catgetoryId],
|
172
|
+
returns: [:id, :name]
|
135
173
|
end
|
136
174
|
|
137
175
|
Product.all
|
@@ -148,6 +186,9 @@ Product.by(id: 1, name: 'Demo Product')
|
|
148
186
|
|
149
187
|
Product.by_category_id(product_category: { id: 10})
|
150
188
|
=> OpenStruct<product_category=<ProductCategory<id=10, name='Demo Category'>>
|
189
|
+
|
190
|
+
Product.create(name: 'Another Product', catgetoryId: 10)
|
191
|
+
=> OpenStruct<id=10, name='Another Product'>
|
151
192
|
```
|
152
193
|
|
153
194
|
Also custom **class methods** can used to call any kind of `query` and do further selection instead:
|
@@ -167,6 +208,9 @@ Product.by_id(id: 1)
|
|
167
208
|
=> OpenStruct<id=1, name='Demo Product'>>
|
168
209
|
```
|
169
210
|
|
211
|
+
:warning: Ensure that your custom **class method** never has the **same name** as an `<alias>` of `add_query`, `add_raw_query` or `add_mutation`. Otherwise the associated grapqhl query will not be performed because of [Ruby Open Class principle](https://ruby-lang.co/ruby-open-class/)
|
212
|
+
|
213
|
+
|
170
214
|
Example for `raw_query`:
|
171
215
|
|
172
216
|
```ruby
|
@@ -188,6 +232,8 @@ Product.by(id: '1', name: 'Demo Product')
|
|
188
232
|
|
189
233
|
```
|
190
234
|
|
235
|
+
:exclamation: There is no `add_raw_mutation` since `add_raw_query` does already cover such a case
|
236
|
+
|
191
237
|
## Development
|
192
238
|
|
193
239
|
After checking out the repo, run
|
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
3
8
|
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
4
9
|
GraphqlConnector.configure do |config|
|
5
10
|
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
@@ -27,6 +32,12 @@ class Department
|
|
27
32
|
}
|
28
33
|
}',
|
29
34
|
params: [:id]
|
35
|
+
|
36
|
+
# We use a nested 'input' as of convention for
|
37
|
+
# https://github.com/sushie1984/rails-graphql-server/blob/master/app/graphql/input_objects/department_attributes.rb
|
38
|
+
add_mutation create: :createDepartment,
|
39
|
+
params: :input,
|
40
|
+
returns: [department: %i[id name location]]
|
30
41
|
end
|
31
42
|
|
32
43
|
Department.all
|
@@ -36,3 +47,5 @@ Department.by_id(id: %w[1 2])
|
|
36
47
|
Department.all_raw
|
37
48
|
|
38
49
|
Department.by_id_raw(id: %w[1 2])
|
50
|
+
|
51
|
+
Department.create(input: { attributes: { name: 'One', location: 'Berlin' } })
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
8
|
+
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
9
|
+
GraphqlConnector.configure do |config|
|
10
|
+
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
11
|
+
end
|
12
|
+
|
13
|
+
department_input = { attributes: { name: 'One', location: 'Berlin' } }
|
14
|
+
return_fields = ['department': ['id', 'name', 'employees' => ['yearlySalary']]]
|
15
|
+
GraphqlConnector::RailsGraphqlServer.mutation('createDepartment',
|
16
|
+
{ input: department_input },
|
17
|
+
return_fields)
|
data/examples/query_examples.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
3
8
|
uri = 'http://rails-graphql-server.herokuapp.com/api/graphql'
|
4
9
|
GraphqlConnector.configure do |config|
|
5
10
|
config.add_server(name: 'RailsGraphqlServer', uri: uri, headers: {})
|
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
4
|
+
# ! The following examples are used together with
|
5
|
+
# ! https://github.com/sushie1984/rails-graphql-server
|
6
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
7
|
+
|
3
8
|
GraphqlConnector.configure do |config|
|
4
9
|
config.add_server(name: 'RailsGraphqlServer',
|
5
10
|
uri: 'http://rails-graphql-server.herokuapp.com/api/graphql',
|
data/graphql_connector.gemspec
CHANGED
@@ -31,11 +31,10 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
32
|
spec.require_paths = ['lib']
|
33
33
|
|
34
|
-
spec.add_dependency 'httparty', '~> 0.
|
34
|
+
spec.add_dependency 'httparty', '~> 0.16'
|
35
35
|
|
36
36
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
37
37
|
spec.add_development_dependency 'pry', '~> 0.10'
|
38
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
39
38
|
spec.add_development_dependency 'rspec', '~> 3.8'
|
40
39
|
spec.add_development_dependency 'rubocop', '~> 0.75'
|
41
40
|
end
|
data/lib/graphql_connector.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql_connector/version'
|
4
|
-
require 'graphql_connector/
|
4
|
+
require 'graphql_connector/formatters/base_format'
|
5
|
+
require 'graphql_connector/formatters/query_format'
|
6
|
+
require 'graphql_connector/formatters/mutation_format'
|
5
7
|
require 'graphql_connector/configuration'
|
6
8
|
require 'graphql_connector/http_client'
|
7
9
|
require 'graphql_connector/base_server_type'
|
@@ -5,12 +5,11 @@ module GraphqlConnector
|
|
5
5
|
# Class to wrap http_client calls under a specific namespaced class
|
6
6
|
class BaseServerType
|
7
7
|
class << self
|
8
|
-
def build(name, uri, headers)
|
8
|
+
def build(name, uri, headers = {}, connector = {})
|
9
9
|
verify_new_client_type_for!(name)
|
10
|
-
base_class = class_with(uri, headers)
|
10
|
+
base_class = class_with(uri, headers, connector)
|
11
11
|
base_object = GraphqlConnector.const_set(name, base_class)
|
12
|
-
|
13
|
-
inject_query_methods(base_object)
|
12
|
+
inject_http_client_delegations(base_object)
|
14
13
|
create_service_class_module(base_object)
|
15
14
|
|
16
15
|
base_object
|
@@ -40,30 +39,23 @@ module GraphqlConnector
|
|
40
39
|
METHOD
|
41
40
|
end
|
42
41
|
|
43
|
-
def class_with(uri, headers)
|
42
|
+
def class_with(uri, headers = {}, connector = {})
|
44
43
|
Class.new do
|
45
|
-
attr_accessor :uri, :headers
|
46
|
-
@uri
|
47
|
-
@headers
|
44
|
+
attr_accessor :uri, :headers, :connector
|
45
|
+
@uri = uri
|
46
|
+
@headers = headers
|
47
|
+
@connector = connector
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
51
|
+
def inject_http_client_delegations(base_object)
|
52
52
|
base_object.instance_eval do
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
53
|
+
extend SingleForwardable
|
54
|
+
def_delegators :http_client, :query, :raw_query, :mutation
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
http_client.query(model, conditions, selected_fields)
|
63
|
-
end
|
64
|
-
|
65
|
-
def raw_query(query_string, variables: {})
|
66
|
-
http_client.raw_query(query_string, variables: variables)
|
56
|
+
def http_client
|
57
|
+
@http_client ||=
|
58
|
+
GraphqlConnector::HttpClient.new(@uri, @headers, @connector)
|
67
59
|
end
|
68
60
|
end
|
69
61
|
end
|
@@ -9,8 +9,9 @@ module GraphqlConnector
|
|
9
9
|
@base_server_types = {}
|
10
10
|
end
|
11
11
|
|
12
|
-
def add_server(name:, uri:, headers:)
|
13
|
-
@base_server_types[name] =
|
12
|
+
def add_server(name:, uri:, headers: {}, connector: {})
|
13
|
+
@base_server_types[name] =
|
14
|
+
BaseServerType.build(name, uri, headers, connector)
|
14
15
|
end
|
15
16
|
|
16
17
|
def reset!
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlConnector
|
4
|
+
module Formatters
|
5
|
+
# Class that returns in query or mutation string format
|
6
|
+
class BaseFormat
|
7
|
+
def initialize(model, conditions, selected_fields)
|
8
|
+
@model = model
|
9
|
+
@conditions = conditions
|
10
|
+
@selected_fields = selected_fields
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
<<-STRING
|
15
|
+
#{query_type} {
|
16
|
+
#{@model}#{arguments} {
|
17
|
+
#{parse_fields(@selected_fields)}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
STRING
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def arguments
|
26
|
+
conditions = @conditions.each_with_object([]) do |(key, value), array|
|
27
|
+
array << "#{key}: #{value_as_parameter(value)}"
|
28
|
+
end
|
29
|
+
|
30
|
+
return '' if conditions.empty?
|
31
|
+
|
32
|
+
"(#{conditions.join(', ')})"
|
33
|
+
end
|
34
|
+
|
35
|
+
def value_as_parameter(value)
|
36
|
+
case value
|
37
|
+
when Array
|
38
|
+
casted_values = value.map { |v| value_as_parameter(v) }
|
39
|
+
"[#{casted_values.join(',')}]"
|
40
|
+
when Hash
|
41
|
+
casted_values = value.map { |k, v| "#{k}: #{value_as_parameter(v)}" }
|
42
|
+
"{#{casted_values.join(',')}}"
|
43
|
+
else
|
44
|
+
scalar_types(value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def scalar_types(value)
|
49
|
+
case value
|
50
|
+
when TrueClass, FalseClass, Integer, Float
|
51
|
+
value
|
52
|
+
else # fallback to string
|
53
|
+
'"' + value.to_s + '"'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_fields(selected_fields)
|
58
|
+
results = selected_fields.map do |field|
|
59
|
+
case field
|
60
|
+
when Hash
|
61
|
+
handle_association(field)
|
62
|
+
else
|
63
|
+
field
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
results.join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_association(hash)
|
71
|
+
hash.map do |key, fields|
|
72
|
+
"#{key} { #{parse_fields(fields)} }"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def query_type
|
77
|
+
raise 'query_type undefined'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -3,25 +3,29 @@
|
|
3
3
|
module GraphqlConnector
|
4
4
|
# Wrapper class for HTTParty post query
|
5
5
|
class HttpClient
|
6
|
-
def initialize(uri, headers)
|
6
|
+
def initialize(uri, headers = {}, connector = {})
|
7
7
|
@uri = uri
|
8
8
|
@headers = headers
|
9
|
+
@connector = connector
|
9
10
|
end
|
10
11
|
|
11
12
|
def query(model, conditions, selected_fields)
|
12
|
-
query_string =
|
13
|
-
|
14
|
-
selected_fields).create
|
13
|
+
query_string =
|
14
|
+
Formatters::QueryFormat.new(model, conditions, selected_fields).create
|
15
15
|
parsed_body = raw_query(query_string)
|
16
|
-
|
17
|
-
|
16
|
+
format_body(parsed_body['data'][model.to_s])
|
17
|
+
end
|
18
18
|
|
19
|
-
|
19
|
+
def mutation(model, inputs, selected_fields)
|
20
|
+
query_string =
|
21
|
+
Formatters::MutationFormat.new(model, inputs, selected_fields).create
|
22
|
+
parsed_body = raw_query(query_string)
|
23
|
+
format_body(parsed_body['data'][model.to_s])
|
20
24
|
end
|
21
25
|
|
22
26
|
def raw_query(query_string, variables: {})
|
23
27
|
response = HTTParty.post(@uri,
|
24
|
-
headers:
|
28
|
+
headers: handle_headers,
|
25
29
|
body: { query: query_string,
|
26
30
|
variables: variables })
|
27
31
|
parsed_body = JSON.parse(response.body)
|
@@ -31,6 +35,19 @@ module GraphqlConnector
|
|
31
35
|
|
32
36
|
private
|
33
37
|
|
38
|
+
def handle_headers
|
39
|
+
return @headers if @connector.empty?
|
40
|
+
|
41
|
+
@headers
|
42
|
+
.merge(@connector[:base].public_send(@connector[:method]))
|
43
|
+
end
|
44
|
+
|
45
|
+
def format_body(response_body)
|
46
|
+
return OpenStruct.new(response_body) unless response_body.is_a? Array
|
47
|
+
|
48
|
+
response_body.map { |entry| OpenStruct.new(entry) }
|
49
|
+
end
|
50
|
+
|
34
51
|
def verify_response!(parsed_body)
|
35
52
|
return unless parsed_body.key? 'errors'
|
36
53
|
|
@@ -13,9 +13,9 @@ module GraphqlConnector
|
|
13
13
|
.map(&:to_s)
|
14
14
|
.include?(class_method_name.to_s)
|
15
15
|
|
16
|
-
error_msg = "The
|
16
|
+
error_msg = "The method '#{class_method_name}: ... ' is "\
|
17
17
|
'already implemented within the context of '\
|
18
|
-
"#{invoked_class} and therefore cannot be used!"
|
18
|
+
"#{invoked_class} and therefore cannot be used again!"
|
19
19
|
raise ClassMethodAlreadyImplementedError, error_msg
|
20
20
|
end
|
21
21
|
|
@@ -38,6 +38,21 @@ module GraphqlConnector
|
|
38
38
|
raw_query_keyword_method(class_method_name, query_string, params)
|
39
39
|
end
|
40
40
|
|
41
|
+
def add_mutation(params: [], returns:, **method_to_query)
|
42
|
+
class_method_name = method_to_query.first[0]
|
43
|
+
query_type = method_to_query.first[1]
|
44
|
+
ReturnFieldsValidator.validate(returns)
|
45
|
+
ClassMethodValidator.validate_class_method(class_method_name, self)
|
46
|
+
ClassMethodValidator.validate_element_class_type(query_type, Symbol)
|
47
|
+
|
48
|
+
if params.empty?
|
49
|
+
return mutation_method(class_method_name, query_type, returns)
|
50
|
+
end
|
51
|
+
|
52
|
+
ParamsValidator.validate(params)
|
53
|
+
mutation_keyword_method(class_method_name, query_type, params, returns)
|
54
|
+
end
|
55
|
+
|
41
56
|
private
|
42
57
|
|
43
58
|
def query_method(class_method_name, query_type, return_fields)
|
@@ -71,6 +86,23 @@ module GraphqlConnector
|
|
71
86
|
end
|
72
87
|
METHOD
|
73
88
|
end
|
89
|
+
|
90
|
+
def mutation_method(class_method_name, query_type, return_fields)
|
91
|
+
define_singleton_method class_method_name do
|
92
|
+
http_client.mutation(query_type, {}, return_fields.to_a)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def mutation_keyword_method(name, query_type, keywords, return_fields)
|
97
|
+
keywords = [keywords].flatten
|
98
|
+
instance_eval <<-METHOD, __FILE__, __LINE__ + 1
|
99
|
+
def #{name}(#{keywords.map { |keyword| "#{keyword}:" }.join(', ')})
|
100
|
+
http_client.mutation("#{query_type}",
|
101
|
+
#{CONDITIONS},
|
102
|
+
#{return_fields.to_a})
|
103
|
+
end
|
104
|
+
METHOD
|
105
|
+
end
|
74
106
|
end
|
75
107
|
end
|
76
108
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_connector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Garllon
|
8
8
|
- sushie1984
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-06-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '0.
|
20
|
+
version: '0.16'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '0.
|
27
|
+
version: '0.16'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: bundler
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,20 +53,6 @@ dependencies:
|
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0.10'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: rake
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - "~>"
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '10.0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - "~>"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '10.0'
|
70
56
|
- !ruby/object:Gem::Dependency
|
71
57
|
name: rspec
|
72
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,11 +90,11 @@ executables: []
|
|
104
90
|
extensions: []
|
105
91
|
extra_rdoc_files: []
|
106
92
|
files:
|
93
|
+
- ".github/workflows/ci.yaml"
|
107
94
|
- ".gitignore"
|
108
95
|
- ".rspec"
|
109
96
|
- ".rubocop.yml"
|
110
97
|
- ".rubocop_todo.yml"
|
111
|
-
- ".travis.yml"
|
112
98
|
- CHANGELOG.md
|
113
99
|
- CODE_OF_CONDUCT.md
|
114
100
|
- Gemfile
|
@@ -117,6 +103,7 @@ files:
|
|
117
103
|
- README.md
|
118
104
|
- bin/console
|
119
105
|
- examples/departments_service_class_examples.rb
|
106
|
+
- examples/mutation_examples.rb
|
120
107
|
- examples/query_examples.rb
|
121
108
|
- examples/raw_query_examples.rb
|
122
109
|
- graphql_connector.gemspec
|
@@ -124,8 +111,10 @@ files:
|
|
124
111
|
- lib/graphql_connector/base_server_type.rb
|
125
112
|
- lib/graphql_connector/configuration.rb
|
126
113
|
- lib/graphql_connector/custom_attribute_error.rb
|
114
|
+
- lib/graphql_connector/formatters/base_format.rb
|
115
|
+
- lib/graphql_connector/formatters/mutation_format.rb
|
116
|
+
- lib/graphql_connector/formatters/query_format.rb
|
127
117
|
- lib/graphql_connector/http_client.rb
|
128
|
-
- lib/graphql_connector/query_builder.rb
|
129
118
|
- lib/graphql_connector/service_classable/class_method_validator.rb
|
130
119
|
- lib/graphql_connector/service_classable/params_validator.rb
|
131
120
|
- lib/graphql_connector/service_classable/queryable.rb
|
@@ -138,7 +127,7 @@ metadata:
|
|
138
127
|
homepage_uri: https://github.com/Garllon/graphql_connector/blob/master/README.md
|
139
128
|
source_code_uri: https://github.com/Garllon/graphql_connector
|
140
129
|
changelog_uri: https://github.com/Garllon/graphql_connector/blob/master/CHANGELOG.md
|
141
|
-
post_install_message:
|
130
|
+
post_install_message:
|
142
131
|
rdoc_options: []
|
143
132
|
require_paths:
|
144
133
|
- lib
|
@@ -153,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
142
|
- !ruby/object:Gem::Version
|
154
143
|
version: '0'
|
155
144
|
requirements: []
|
156
|
-
rubygems_version: 3.
|
157
|
-
signing_key:
|
145
|
+
rubygems_version: 3.2.7
|
146
|
+
signing_key:
|
158
147
|
specification_version: 4
|
159
148
|
summary: GraphQL client
|
160
149
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GraphqlConnector
|
4
|
-
# create the graphql query_string out of the given attributes.
|
5
|
-
class QueryBuilder
|
6
|
-
def initialize(model, conditions, selected_fields)
|
7
|
-
@model = model
|
8
|
-
@conditions = conditions
|
9
|
-
@selected_fields = selected_fields
|
10
|
-
end
|
11
|
-
|
12
|
-
def create
|
13
|
-
"query { #{main_filter} { #{parse_fields(@selected_fields)} } }"
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def main_filter
|
19
|
-
conditions = @conditions.each_with_object([]) do |(key, value), array|
|
20
|
-
next if value.is_a? Hash # will be processed in #field_with_filter
|
21
|
-
|
22
|
-
array << "#{key}: #{value_as_parameter(value)}"
|
23
|
-
end
|
24
|
-
|
25
|
-
"#{@model}(#{conditions.join(', ')})"
|
26
|
-
end
|
27
|
-
|
28
|
-
def value_as_parameter(value)
|
29
|
-
case value
|
30
|
-
when TrueClass, FalseClass, Integer, Float
|
31
|
-
value
|
32
|
-
when Array
|
33
|
-
casted_values = value.map { |v| value_as_parameter(v) }
|
34
|
-
"[#{casted_values.join(',')}]"
|
35
|
-
else # fallback to string
|
36
|
-
'"' + value.to_s + '"'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def parse_fields(selected_fields)
|
41
|
-
results = selected_fields.map do |field|
|
42
|
-
case field
|
43
|
-
when Hash
|
44
|
-
handle_association(field)
|
45
|
-
else
|
46
|
-
field
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
results.join(' ')
|
51
|
-
end
|
52
|
-
|
53
|
-
def handle_association(hash)
|
54
|
-
hash.map do |key, fields|
|
55
|
-
"#{key} { #{parse_fields(fields)} }"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|