graphlient 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa3b9416b7374b0c3881224177f2a5646432e27ce9fcfdb2454b31ba318e231a
4
- data.tar.gz: 6ca64471c0129dc021248fa309ed187bde0c9f9e58cf07a98d9072768e5446fe
3
+ metadata.gz: ed5f47ad98345af440481f9dca800767524807bc667eace999d7ba36826e59fa
4
+ data.tar.gz: 22ec20f5b725b3bb85bc9c8e8371693824f7fd85b2db43336ce7f6a6be31543f
5
5
  SHA512:
6
- metadata.gz: f035b28bfd747c72574b124cd5130e92798ac6b14d9000b73c6ce25357489f23ded22ca11dd74cc777c96dfeada948f86a9dd3b754838abf230cf82849e8f893
7
- data.tar.gz: e6fd794359759c72051ddd7114fbe85c1110d0b743f55cd521cdcbb56fc9e6cecd4a70b6a6383f76d5304fd542d889e965d28738394995282768794059067b6c
6
+ metadata.gz: 1c5ddbaafe24dfbdd6e99535bedb7a021eba55a956b4b716661c9c8778018a96118afc5a6def029aad14da883de8d47a747b4a85ead2cee0868d5ddcfb298359
7
+ data.tar.gz: 3fd8b40976687fd83b00b865f62d514a87571de0bf68015486328d526a2d9cc76a8c4454a5d78f86acba6480860ac1abde3ff2edda1e92c26b03c58f60b067e2
@@ -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.1.17", ignore: true }
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 NWY1ZmM5MzEyMzNlYWY4OTZiOGU3MmI3MWQ3Mzk0MzgxMWE4OGVmYwo= | base64 --decode)
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 storing and loading on disk](#schema-storing-and-loading-on-disk)
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
- ___Graphlient__InvoiceFragment
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
- response.body
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Graphlient
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -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.7.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: 2022-10-11 00:00:00.000000000 Z
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.1.4
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.