graphlient 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -1
- data/.github/workflows/danger.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +27 -2
- data/lib/graphlient/adapters/http/faraday_adapter.rb +35 -1
- data/lib/graphlient/client.rb +8 -1
- data/lib/graphlient/version.rb +1 -1
- data/spec/graphlient/adapters/http/faraday_adapter_spec.rb +55 -0
- data/spec/graphlient/client_schema_spec.rb +20 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed5f47ad98345af440481f9dca800767524807bc667eace999d7ba36826e59fa
|
4
|
+
data.tar.gz: 22ec20f5b725b3bb85bc9c8e8371693824f7fd85b2db43336ce7f6a6be31543f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c5ddbaafe24dfbdd6e99535bedb7a021eba55a956b4b716661c9c8778018a96118afc5a6def029aad14da883de8d47a747b4a85ead2cee0868d5ddcfb298359
|
7
|
+
data.tar.gz: 3fd8b40976687fd83b00b865f62d514a87571de0bf68015486328d526a2d9cc76a8c4454a5d78f86acba6480860ac1abde3ff2edda1e92c26b03c58f60b067e2
|
data/.github/workflows/ci.yml
CHANGED
@@ -14,8 +14,9 @@ jobs:
|
|
14
14
|
- { ruby: 2.7.2 }
|
15
15
|
- { ruby: 3.0.0 }
|
16
16
|
- { ruby: 3.1.2 }
|
17
|
+
- { ruby: 3.2.2 }
|
17
18
|
- { ruby: "ruby-head", ignore: true }
|
18
|
-
- { ruby: "jruby-9.
|
19
|
+
- { ruby: "jruby-9.3.9.0", ignore: true }
|
19
20
|
- { ruby: "jruby-head", ignore: true }
|
20
21
|
steps:
|
21
22
|
- uses: actions/checkout@v3
|
@@ -18,5 +18,5 @@ jobs:
|
|
18
18
|
bundler-cache: true
|
19
19
|
- run: |
|
20
20
|
# the personal token is public, this is ok, base64 encode to avoid tripping Github
|
21
|
-
TOKEN=$(echo -n
|
21
|
+
TOKEN=$(echo -n Z2hwX0xNQ3VmanBFeTBvYkZVTWh6NVNqVFFBOEUxU25abzBqRUVuaAo= | base64 --decode)
|
22
22
|
DANGER_GITHUB_API_TOKEN=$TOKEN bundle exec danger --verbose
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
### (Next)
|
2
2
|
* Your contribution here.
|
3
3
|
|
4
|
+
### 0.8.0 (2024/01/06)
|
5
|
+
* [#110](https://github.com/ashkan18/graphlient/pull/110): Ensure correct Faraday JSON response body parsing with invalid response header - [@taylorthurlow](https://github.com/taylorthurlow).
|
6
|
+
* [#107](https://github.com/ashkan18/graphlient/pull/107): Pass in initialized schema as an option - [@kbaum](https://github.com/kbaum).
|
7
|
+
* [#106](https://github.com/ashkan18/graphlient/pull/106): Add 3.2 to the list of ruby ci versions - [@igor-drozdov](https://github.com/igor-drozdov).
|
8
|
+
* [#102](https://github.com/ashkan18/graphlient/pull/102): Update ci to test latest jruby - [@ashkan18](https://github.com/ashkan18).
|
9
|
+
|
4
10
|
### 0.7.0 (2022/10/11)
|
5
11
|
* [#98](https://github.com/ashkan18/graphlient/pull/98): Bring back danger checks and improve them - [@ashkan18](https://github.com/ashkan18).
|
6
12
|
* [#94](https://github.com/ashkan18/graphlient/pull/94): Enabled fragments - [@rellampec](https://github.com/rellampec).
|
data/README.md
CHANGED
@@ -9,7 +9,8 @@ A friendlier Ruby client for consuming GraphQL-based APIs. Built on top of your
|
|
9
9
|
|
10
10
|
- [Installation](#installation)
|
11
11
|
- [Usage](#usage)
|
12
|
-
- [Schema
|
12
|
+
- [Schema Storing and Loading on Disk](#schema-storing-and-loading-on-disk)
|
13
|
+
- [Preloading Schema Once](#preloading-schema-once)
|
13
14
|
- [Error Handling](#error-handling)
|
14
15
|
- [Executing Parameterized Queries and Mutations](#executing-parameterized-queries-and-mutations)
|
15
16
|
- [Parse and Execute Queries Separately](#parse-and-execute-queries-separately)
|
@@ -140,6 +141,30 @@ client = Client.new(url, schema_path: 'config/your_graphql_schema.json')
|
|
140
141
|
client.schema.dump! # you only need to call this when graphql schema changes
|
141
142
|
```
|
142
143
|
|
144
|
+
### Preloading Schema Once
|
145
|
+
|
146
|
+
Even if caching the schema on disk, instantiating `Graphlient::Client` often can be both time and memory intensive due to loading the schema for each instance. This is especially true if the schema is a large file. To get around these performance issues, instantiate your schema once and pass it in as a configuration option.
|
147
|
+
|
148
|
+
One time in an initializer
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
schema = Graphlient::Schema.new(
|
152
|
+
'https://graphql.foo.com/graphql', 'lib/graphql_schema_foo.json'
|
153
|
+
)
|
154
|
+
```
|
155
|
+
|
156
|
+
Pass in each time you initialize a client
|
157
|
+
|
158
|
+
```
|
159
|
+
client = Graphlient::Client.new(
|
160
|
+
'https://graphql.foo.com/graphql',
|
161
|
+
schema: schema,
|
162
|
+
headers: {
|
163
|
+
'Authorization' => 'Bearer 123',
|
164
|
+
}
|
165
|
+
)
|
166
|
+
```
|
167
|
+
|
143
168
|
### Error Handling
|
144
169
|
|
145
170
|
Unlike graphql-client, Graphlient will always raise an exception unless the query has succeeded.
|
@@ -341,7 +366,7 @@ invoice_query = client.parse do
|
|
341
366
|
query do
|
342
367
|
invoice(id: 10) do
|
343
368
|
id
|
344
|
-
|
369
|
+
___Fragments__Invoice
|
345
370
|
end
|
346
371
|
end
|
347
372
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'faraday'
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module Graphlient
|
4
5
|
module Adapters
|
@@ -13,7 +14,8 @@ module Graphlient
|
|
13
14
|
variables: variables
|
14
15
|
}.to_json
|
15
16
|
end
|
16
|
-
|
17
|
+
|
18
|
+
parse_body(response.body)
|
17
19
|
rescue Faraday::ConnectionFailed => e
|
18
20
|
raise Graphlient::Errors::ConnectionFailedError, e
|
19
21
|
rescue Faraday::TimeoutError => e
|
@@ -39,6 +41,38 @@ module Graphlient
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Faraday 2.x's JSON response middleware will only parse a JSON
|
48
|
+
# response body into a Hash (or Array) object if the response headers
|
49
|
+
# match a specific content type regex. See Faraday's response JSON
|
50
|
+
# middleware definition for specifics on what the datatype of the
|
51
|
+
# response body will be. This method will handle the situation where
|
52
|
+
# the response header is not set appropriately, but contains JSON
|
53
|
+
# anyways. If the body cannot be parsed as JSON, an exception will be
|
54
|
+
# raised.
|
55
|
+
def parse_body(body)
|
56
|
+
case body
|
57
|
+
when Hash, Array
|
58
|
+
body
|
59
|
+
when String
|
60
|
+
begin
|
61
|
+
JSON.parse(body)
|
62
|
+
rescue JSON::ParserError
|
63
|
+
raise Graphlient::Errors::ServerError, 'Failed to parse response body as JSON'
|
64
|
+
end
|
65
|
+
else
|
66
|
+
inner_exception = StandardError.new <<~ERR.strip.tr("\n", ' ')
|
67
|
+
Unexpected response body type '#{body.class}'. Graphlient doesn't
|
68
|
+
know how to handle a response body of this type, but Faraday is
|
69
|
+
returning it. Please open an issue, particularly if the response
|
70
|
+
body does actually contain valid JSON.
|
71
|
+
ERR
|
72
|
+
|
73
|
+
raise Graphlient::Errors::ClientError, inner_exception
|
74
|
+
end
|
75
|
+
end
|
42
76
|
end
|
43
77
|
end
|
44
78
|
end
|
data/lib/graphlient/client.rb
CHANGED
@@ -2,9 +2,12 @@ module Graphlient
|
|
2
2
|
class Client
|
3
3
|
attr_accessor :uri, :options
|
4
4
|
|
5
|
+
class InvalidConfigurationError < StandardError; end
|
6
|
+
|
5
7
|
def initialize(url, options = {}, &_block)
|
6
8
|
@url = url
|
7
9
|
@options = options.dup
|
10
|
+
raise_error_if_invalid_configuration!
|
8
11
|
yield self if block_given?
|
9
12
|
end
|
10
13
|
|
@@ -51,11 +54,15 @@ module Graphlient
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def schema
|
54
|
-
@schema ||= Graphlient::Schema.new(http, schema_path)
|
57
|
+
@schema ||= options[:schema] || Graphlient::Schema.new(http, schema_path)
|
55
58
|
end
|
56
59
|
|
57
60
|
private
|
58
61
|
|
62
|
+
def raise_error_if_invalid_configuration!
|
63
|
+
raise InvalidConfigurationError, 'schema_path and schema cannot both be provided' if options.key?(:schema_path) && options.key?(:schema)
|
64
|
+
end
|
65
|
+
|
59
66
|
def schema_path
|
60
67
|
return options[:schema_path].to_s if options[:schema_path]
|
61
68
|
end
|
data/lib/graphlient/version.rb
CHANGED
@@ -75,6 +75,61 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
context 'a non-error response without an appropriate JSON header' do
|
79
|
+
let(:url) { 'http://example.com/graphql' }
|
80
|
+
let(:headers) { { 'Content-Type' => 'application/notjson' } }
|
81
|
+
let(:client) { Graphlient::Client.new(url) }
|
82
|
+
let(:response_headers) { { 'Content-Type' => 'application/notjson' } }
|
83
|
+
|
84
|
+
context 'when the response body is valid JSON' do
|
85
|
+
before do
|
86
|
+
stub_request(:post, url).to_return(
|
87
|
+
status: 200,
|
88
|
+
headers: response_headers,
|
89
|
+
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'retrieves schema' do
|
94
|
+
expect(client.schema).to be_a Graphlient::Schema
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when the response body is not valid JSON' do
|
99
|
+
before do
|
100
|
+
stub_request(:post, url).to_return(
|
101
|
+
status: 200,
|
102
|
+
headers: response_headers,
|
103
|
+
body: ''
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'raises Graphlient::Errors::ServerError' do
|
108
|
+
expect { client.schema }.to raise_error(Graphlient::Errors::ServerError) { |error|
|
109
|
+
expect(error.message).to include('Failed to parse response body as JSON')
|
110
|
+
}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when the Faraday response body object is not a type we expect from Faraday' do
|
115
|
+
before do
|
116
|
+
stub_request(:post, url).to_return(
|
117
|
+
status: 200,
|
118
|
+
headers: response_headers
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'raises Graphlient::Errors::ClientError' do
|
123
|
+
mock_response = double('response', body: nil)
|
124
|
+
allow(client.http.connection).to receive(:post).and_return(mock_response)
|
125
|
+
|
126
|
+
expect { client.schema }.to raise_error(Graphlient::Errors::ClientError) { |error|
|
127
|
+
expect(error.message).to include "Unexpected response body type 'NilClass'"
|
128
|
+
}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
78
133
|
context 'Failed to open TCP connection error' do
|
79
134
|
let(:url) { 'http://example.com/graphql' }
|
80
135
|
let(:client) { Graphlient::Client.new(url) }
|
@@ -51,5 +51,25 @@ describe Graphlient::Client do
|
|
51
51
|
expect(client.schema.path).to eq 'config/schema.json'
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
context 'when preloaded schema is provided' do
|
56
|
+
let(:schema) { Graphlient::Schema.new(url, 'spec/support/fixtures/invoice_api.json') }
|
57
|
+
let(:client) { described_class.new(url, schema: schema) }
|
58
|
+
|
59
|
+
it 'returns the passed in schema' do
|
60
|
+
expect(client.schema).not_to be_nil
|
61
|
+
expect(client.schema).to eq(schema)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when and a schema and a schema path are provided' do
|
66
|
+
let(:schema) { Graphlient::Schema.new(url, 'spec/support/fixtures/invoice_api.json') }
|
67
|
+
let(:client) { described_class.new(url, schema: schema, schema_path: 'spec/support/fixtures/invoice_api.json') }
|
68
|
+
|
69
|
+
it 'raises an invalid configuration error' do
|
70
|
+
expect { client }.to raise_error(Graphlient::Client::InvalidConfigurationError,
|
71
|
+
/schema_path and schema cannot both be provided/)
|
72
|
+
end
|
73
|
+
end
|
54
74
|
end
|
55
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphlient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.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:
|
11
|
+
date: 2024-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -131,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
131
|
- !ruby/object:Gem::Version
|
132
132
|
version: 1.3.6
|
133
133
|
requirements: []
|
134
|
-
rubygems_version: 3.
|
134
|
+
rubygems_version: 3.3.7
|
135
135
|
signing_key:
|
136
136
|
specification_version: 4
|
137
137
|
summary: A friendlier Ruby client for consuming GraphQL-based APIs.
|