graphlient 0.6.0 → 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/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/danger.yml +2 -0
- data/CHANGELOG.md +8 -0
- data/Dangerfile +24 -1
- data/Gemfile +1 -1
- data/Gemfile.danger +5 -0
- data/README.md +71 -0
- data/graphlient.gemspec +1 -2
- data/lib/graphlient/adapters/http/faraday_adapter.rb +0 -1
- data/lib/graphlient/query.rb +21 -2
- data/lib/graphlient/version.rb +1 -1
- data/spec/graphlient/adapters/http/faraday_adapter_spec.rb +4 -4
- data/spec/graphlient/client_query_spec.rb +37 -0
- data/spec/graphlient/client_schema_spec.rb +13 -3
- data/spec/graphlient/schema_spec.rb +4 -1
- data/spec/graphlient/webmock_client_query_spec.rb +2 -1
- data/spec/spec_helper.rb +1 -0
- metadata +10 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa3b9416b7374b0c3881224177f2a5646432e27ce9fcfdb2454b31ba318e231a
|
4
|
+
data.tar.gz: 6ca64471c0129dc021248fa309ed187bde0c9f9e58cf07a98d9072768e5446fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f035b28bfd747c72574b124cd5130e92798ac6b14d9000b73c6ce25357489f23ded22ca11dd74cc777c96dfeada948f86a9dd3b754838abf230cf82849e8f893
|
7
|
+
data.tar.gz: e6fd794359759c72051ddd7114fbe85c1110d0b743f55cd521cdcbb56fc9e6cecd4a70b6a6383f76d5304fd542d889e965d28738394995282768794059067b6c
|
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior:
|
15
|
+
1. Go to '...'
|
16
|
+
2. Click on '....'
|
17
|
+
3. Scroll down to '....'
|
18
|
+
4. See error
|
19
|
+
|
20
|
+
**Expected behavior**
|
21
|
+
A clear and concise description of what you expected to happen.
|
22
|
+
|
23
|
+
**Screenshots**
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
25
|
+
|
26
|
+
**Desktop (please complete the following information):**
|
27
|
+
- OS: [e.g. iOS]
|
28
|
+
- Browser [e.g. chrome, safari]
|
29
|
+
- Version [e.g. 22]
|
30
|
+
|
31
|
+
**Smartphone (please complete the following information):**
|
32
|
+
- Device: [e.g. iPhone6]
|
33
|
+
- OS: [e.g. iOS8.1]
|
34
|
+
- Browser [e.g. stock browser, safari]
|
35
|
+
- Version [e.g. 22]
|
36
|
+
|
37
|
+
**Additional context**
|
38
|
+
Add any other context about the problem here.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
12
|
+
|
13
|
+
**Describe the solution you'd like**
|
14
|
+
A clear and concise description of what you want to happen.
|
15
|
+
|
16
|
+
**Describe alternatives you've considered**
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
18
|
+
|
19
|
+
**Additional context**
|
20
|
+
Add any other context or screenshots about the feature request here.
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
### (Next)
|
2
|
+
* Your contribution here.
|
3
|
+
|
4
|
+
### 0.7.0 (2022/10/11)
|
5
|
+
* [#98](https://github.com/ashkan18/graphlient/pull/98): Bring back danger checks and improve them - [@ashkan18](https://github.com/ashkan18).
|
6
|
+
* [#94](https://github.com/ashkan18/graphlient/pull/94): Enabled fragments - [@rellampec](https://github.com/rellampec).
|
7
|
+
* [#95](https://github.com/ashkan18/graphlient/pull/95): Upgrade faraday dependency to version 2 - [@kirillkaiumov](https://github.com/kirillkaiumov).
|
8
|
+
|
1
9
|
### 0.6.0 (2022/06/11)
|
2
10
|
|
3
11
|
* [#87](https://github.com/ashkan18/graphlient/pull/87): Raised `ExecutionError` with partial error response - [@QQism](https://github.com/QQism).
|
data/Dangerfile
CHANGED
@@ -1 +1,24 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# --------------------------------------------------------------------------------------------------------------------
|
4
|
+
# Has any changes happened inside the actual library code?
|
5
|
+
# --------------------------------------------------------------------------------------------------------------------
|
6
|
+
has_app_changes = !git.modified_files.grep(/lib/).empty?
|
7
|
+
has_spec_changes = !git.modified_files.grep(/spec/).empty?
|
8
|
+
|
9
|
+
# --------------------------------------------------------------------------------------------------------------------
|
10
|
+
# You've made changes to lib, but didn't write any tests?
|
11
|
+
# --------------------------------------------------------------------------------------------------------------------
|
12
|
+
warn("There're library changes, but not tests. That's OK as long as you're refactoring existing code.", sticky: false) if has_app_changes && !has_spec_changes
|
13
|
+
|
14
|
+
# --------------------------------------------------------------------------------------------------------------------
|
15
|
+
# You've made changes to specs, but no library code has changed?
|
16
|
+
# --------------------------------------------------------------------------------------------------------------------
|
17
|
+
if !has_app_changes && has_spec_changes
|
18
|
+
message('We really appreciate pull requests that demonstrate issues, even without a fix. That said, the next step is to try and fix the failing tests!', sticky: false)
|
19
|
+
end
|
20
|
+
|
21
|
+
# --------------------------------------------------------------------------------------------------------------------
|
22
|
+
# Have you updated CHANGELOG.md?
|
23
|
+
# --------------------------------------------------------------------------------------------------------------------
|
24
|
+
changelog.check!
|
data/Gemfile
CHANGED
@@ -10,11 +10,11 @@ end
|
|
10
10
|
|
11
11
|
group :development do
|
12
12
|
gem 'byebug', platform: :ruby
|
13
|
-
gem 'danger-changelog', '~> 0.2.1'
|
14
13
|
gem 'rubocop', '0.56.0'
|
15
14
|
end
|
16
15
|
|
17
16
|
group :test do
|
17
|
+
gem 'faraday-rack', '~> 2.0'
|
18
18
|
gem 'graphql', '~> 1.9'
|
19
19
|
gem 'graphql-errors'
|
20
20
|
gem 'rack-parser'
|
data/Gemfile.danger
ADDED
data/README.md
CHANGED
@@ -5,6 +5,21 @@
|
|
5
5
|
|
6
6
|
A friendlier Ruby client for consuming GraphQL-based APIs. Built on top of your usual [graphql-client](https://github.com/github/graphql-client), but with better defaults, more consistent error handling, and using the [faraday](https://github.com/lostisland/faraday) HTTP client.
|
7
7
|
|
8
|
+
# Table of Contents
|
9
|
+
|
10
|
+
- [Installation](#installation)
|
11
|
+
- [Usage](#usage)
|
12
|
+
- [Schema storing and loading on disk](#schema-storing-and-loading-on-disk)
|
13
|
+
- [Error Handling](#error-handling)
|
14
|
+
- [Executing Parameterized Queries and Mutations](#executing-parameterized-queries-and-mutations)
|
15
|
+
- [Parse and Execute Queries Separately](#parse-and-execute-queries-separately)
|
16
|
+
- [Dynamic vs. Static Queries](#dynamic-vs-static-queries)
|
17
|
+
- [Generate Queries with Graphlient::Query](#generate-queries-with-graphlientquery)
|
18
|
+
- [Create API Client Classes with Graphlient::Extension::Query](#create-api-client-classes-with-graphlientextensionquery)
|
19
|
+
- [Swapping the HTTP Stack](#swapping-the-http-stack)
|
20
|
+
- [Testing with Graphlient and RSpec](#testing-with-graphlient-and-rspec)
|
21
|
+
- [License](#license)
|
22
|
+
|
8
23
|
## Installation
|
9
24
|
|
10
25
|
Add the following line to your Gemfile.
|
@@ -300,6 +315,62 @@ query.to_s
|
|
300
315
|
# "\nquery {\n invoice(id: 10){\n line_items\n }\n }\n"
|
301
316
|
```
|
302
317
|
|
318
|
+
### Use of Fragments
|
319
|
+
|
320
|
+
[Fragments](https://github.com/github/graphql-client#defining-queries) should be referred by constant:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
module Fragments
|
324
|
+
Invoice = client.parse <<~'GRAPHQL'
|
325
|
+
fragment on Invoice {
|
326
|
+
id
|
327
|
+
feeInCents
|
328
|
+
}
|
329
|
+
GRAPHQL
|
330
|
+
end
|
331
|
+
```
|
332
|
+
|
333
|
+
`Graphlient` offers the syntax below to refer to the original constant:
|
334
|
+
* Triple underscore `___` to refer to the fragment
|
335
|
+
* Double underscore `__` for namespace separator
|
336
|
+
|
337
|
+
In this example, `Fragments::Invoice` would be referred as follows:
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
invoice_query = client.parse do
|
341
|
+
query do
|
342
|
+
invoice(id: 10) do
|
343
|
+
id
|
344
|
+
___Graphlient__InvoiceFragment
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
The wrapped response only allows access to fields that have been explicitly asked for.
|
351
|
+
In this example, while `id` has been referenced directly in the main query, `feeInCents` has been spread via fragment and trying to access it in the original wrapped response will throw [`GraphQL::Client::ImplicitlyFetchedFieldError`](https://github.com/github/graphql-client/blob/master/guides/implicitly-fetched-field-error.md) (to prevent data leaks between components).
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
response = client.execute(invoice_query)
|
355
|
+
result = response.data.invoice
|
356
|
+
result.to_h
|
357
|
+
# {"id" => 10, "feeInCents"=> 20000}
|
358
|
+
result.id
|
359
|
+
# 10
|
360
|
+
result.fee_in_cents
|
361
|
+
# raises GraphQL::Client::ImplicitlyFetchedFieldError
|
362
|
+
```
|
363
|
+
|
364
|
+
`feeInCents` cannot be fetched directly from the main query, but from the fragment as shown below:
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
invoice = Fragments::Invoice.new(result)
|
368
|
+
invoice.id
|
369
|
+
# 10
|
370
|
+
invoice.fee_in_cents
|
371
|
+
# 20000
|
372
|
+
```
|
373
|
+
|
303
374
|
### Create API Client Classes with Graphlient::Extension::Query
|
304
375
|
|
305
376
|
You can include `Graphlient::Extensions::Query` in your class. This will add a new `method_missing` method to your context which will be used to generate GraphQL queries.
|
data/graphlient.gemspec
CHANGED
@@ -14,7 +14,6 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.homepage = 'http://github.com/ashkan18/graphlient'
|
15
15
|
s.licenses = ['MIT']
|
16
16
|
s.summary = 'A friendlier Ruby client for consuming GraphQL-based APIs.'
|
17
|
-
s.add_dependency 'faraday', '
|
18
|
-
s.add_dependency 'faraday_middleware'
|
17
|
+
s.add_dependency 'faraday', '~> 2.0'
|
19
18
|
s.add_dependency 'graphql-client'
|
20
19
|
end
|
data/lib/graphlient/query.rb
CHANGED
@@ -9,13 +9,15 @@ module Graphlient
|
|
9
9
|
|
10
10
|
ROOT_NODES = %w[query mutation subscription].freeze
|
11
11
|
|
12
|
+
FRAGMENT_DEFITION = /___(?<const>[A-Z][a-zA-Z0-9_]*(__[A-Z][a-zA-Z0-9_]*)*)/
|
13
|
+
|
12
14
|
attr_accessor :query_str
|
13
15
|
|
14
16
|
def initialize(&block)
|
15
17
|
@indents = 0
|
16
18
|
@query_str = ''
|
17
19
|
@variables = []
|
18
|
-
|
20
|
+
evaluate(&block)
|
19
21
|
end
|
20
22
|
|
21
23
|
def method_missing(method_name, *args, &block)
|
@@ -39,7 +41,24 @@ module Graphlient
|
|
39
41
|
|
40
42
|
private
|
41
43
|
|
44
|
+
def evaluate(&block)
|
45
|
+
@last_block = block || self
|
46
|
+
(@context ||= {})[@last_block] ||= @last_block.binding
|
47
|
+
instance_eval(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def resolve_fragment_constant(value)
|
51
|
+
return nil unless (match = value.to_s.match(FRAGMENT_DEFITION))
|
52
|
+
raw_const = match[:const].gsub('__', '::')
|
53
|
+
@context[@last_block].eval(raw_const).tap do |const|
|
54
|
+
msg = "Expected constant #{raw_const} to be GraphQL::Client::FragmentDefinition. Given #{const.class}"
|
55
|
+
raise Graphlient::Errors::Error, msg unless const.is_a? GraphQL::Client::FragmentDefinition
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
42
59
|
def append_node(node, args, arg_processor: nil, &block)
|
60
|
+
node = "...#{resolve_fragment_constant(node)}".to_sym if node.to_s.start_with?('___')
|
61
|
+
|
43
62
|
# add field
|
44
63
|
@query_str << "\n#{indent}#{node}"
|
45
64
|
# add filter
|
@@ -49,7 +68,7 @@ module Graphlient
|
|
49
68
|
if block_given?
|
50
69
|
@indents += 1
|
51
70
|
@query_str << '{'
|
52
|
-
|
71
|
+
evaluate(&block)
|
53
72
|
@query_str << '}'
|
54
73
|
@indents -= 1
|
55
74
|
end
|
data/lib/graphlient/version.rb
CHANGED
@@ -19,8 +19,8 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
|
|
19
19
|
expect(client.http.connection.builder.handlers).to eq(
|
20
20
|
[
|
21
21
|
Faraday::Response::RaiseError,
|
22
|
-
|
23
|
-
|
22
|
+
Faraday::Request::Json,
|
23
|
+
Faraday::Response::Json
|
24
24
|
]
|
25
25
|
)
|
26
26
|
end
|
@@ -65,7 +65,8 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
|
|
65
65
|
before do
|
66
66
|
stub_request(:post, url).to_return(
|
67
67
|
status: 200,
|
68
|
-
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
|
68
|
+
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json,
|
69
|
+
headers: { 'Content-Type' => 'application/json' }
|
69
70
|
)
|
70
71
|
end
|
71
72
|
|
@@ -90,7 +91,6 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
|
|
90
91
|
|
91
92
|
specify do
|
92
93
|
expected_error_message = "Connection refused - #{error_message}"
|
93
|
-
|
94
94
|
expect { client.schema }.to raise_error(Graphlient::Errors::ConnectionFailedError, expected_error_message)
|
95
95
|
end
|
96
96
|
end
|
@@ -25,6 +25,43 @@ describe Graphlient::Client do
|
|
25
25
|
invoice = response.data.invoice
|
26
26
|
expect(invoice.id).to eq '10'
|
27
27
|
end
|
28
|
+
|
29
|
+
context 'with fragment' do
|
30
|
+
let(:invoice_fragment) do
|
31
|
+
client.parse <<~'GRAPHQL'
|
32
|
+
fragment on Invoice {
|
33
|
+
id
|
34
|
+
feeInCents
|
35
|
+
}
|
36
|
+
GRAPHQL
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:invoice_fragment_const) do
|
40
|
+
stub_const('Graphlient::InvoiceFragment', invoice_fragment)
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:query) do
|
44
|
+
invoice_fragment_const
|
45
|
+
client.parse do
|
46
|
+
query do
|
47
|
+
invoice(id: 10) do
|
48
|
+
___Graphlient__InvoiceFragment
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it '#parse' do
|
55
|
+
expect(query).to be_a GraphQL::Client::OperationDefinition
|
56
|
+
end
|
57
|
+
|
58
|
+
it '#execute' do
|
59
|
+
response = client.execute(query)
|
60
|
+
invoice = response.data.invoice
|
61
|
+
fragment = invoice_fragment.new(invoice)
|
62
|
+
expect(fragment.id).to eq '10'
|
63
|
+
end
|
64
|
+
end
|
28
65
|
end
|
29
66
|
|
30
67
|
context 'parameterized query' do
|
@@ -7,13 +7,23 @@ describe Graphlient::Client do
|
|
7
7
|
|
8
8
|
describe '#schema' do
|
9
9
|
before do
|
10
|
-
stub_request(:post, url)
|
11
|
-
|
10
|
+
stub_request(:post, url).to_return(
|
11
|
+
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json,
|
12
|
+
headers: { 'Content-Type' => 'application/json' }
|
13
|
+
)
|
12
14
|
end
|
13
15
|
|
14
16
|
context 'when server returns error' do
|
15
17
|
before do
|
16
|
-
stub_request(:post, url).to_return(
|
18
|
+
stub_request(:post, url).to_return(
|
19
|
+
status: 500,
|
20
|
+
body: {
|
21
|
+
errors: [
|
22
|
+
{ message: 'test message', extensions: { code: 'SOMETHING', timestamp: Time.now } }
|
23
|
+
]
|
24
|
+
}.to_json,
|
25
|
+
headers: { 'Content-Type' => 'application/json' }
|
26
|
+
)
|
17
27
|
end
|
18
28
|
|
19
29
|
it 'fails with an exception' do
|
@@ -10,7 +10,10 @@ describe Graphlient::Schema do
|
|
10
10
|
let!(:introspection_query_request) do
|
11
11
|
stub_request(:post, url)
|
12
12
|
.with(body: /query IntrospectionQuery/)
|
13
|
-
.to_return(
|
13
|
+
.to_return(
|
14
|
+
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json,
|
15
|
+
headers: { 'Content-Type' => 'application/json' }
|
16
|
+
)
|
14
17
|
end
|
15
18
|
|
16
19
|
context 'when schema path is not given' do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphlient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ashkan Nasseri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: faraday_middleware
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
24
|
+
- - "~>"
|
32
25
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
26
|
+
version: '2.0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: graphql-client
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +44,8 @@ executables: []
|
|
58
44
|
extensions: []
|
59
45
|
extra_rdoc_files: []
|
60
46
|
files:
|
47
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
48
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
61
49
|
- ".github/workflows/ci.yml"
|
62
50
|
- ".github/workflows/danger.yml"
|
63
51
|
- ".github/workflows/rubocop.yml"
|
@@ -69,6 +57,7 @@ files:
|
|
69
57
|
- CONTRIBUTING.md
|
70
58
|
- Dangerfile
|
71
59
|
- Gemfile
|
60
|
+
- Gemfile.danger
|
72
61
|
- LICENSE
|
73
62
|
- README.md
|
74
63
|
- RELEASING.md
|
@@ -142,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
131
|
- !ruby/object:Gem::Version
|
143
132
|
version: 1.3.6
|
144
133
|
requirements: []
|
145
|
-
rubygems_version: 3.1.
|
134
|
+
rubygems_version: 3.1.4
|
146
135
|
signing_key:
|
147
136
|
specification_version: 4
|
148
137
|
summary: A friendlier Ruby client for consuming GraphQL-based APIs.
|