graphlient 0.3.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7ed6aeee8ae9bf6da765d8142a11387f17bfff3f
4
- data.tar.gz: 084a33299652bb41bd08b83dd752a9703f0d7c58
2
+ SHA256:
3
+ metadata.gz: c049e978a0c48e45fe84d49470bc890ae3b6ea86b86aab8158322616c62968dd
4
+ data.tar.gz: c7307c2b5c6ac6ac2b55ee4d416bbfffee1e29ed0826916254077add10370ee9
5
5
  SHA512:
6
- metadata.gz: af15ee7373138bea76bf1d01beacdafa28ad50240974539c1fd33b3513a571253ce3df7b8739f4fbbd1ff3cbbe776af51c5c719c7ac68bc46e011d72cd97a3b1
7
- data.tar.gz: 4711176bd83a7d24d13ee8bef46ab8eaf54473d03da06912a00a1c4bb544057285801765e753ea5225e073f3e9bbcaf8f1769c75efc203767525f6a120354c44
6
+ metadata.gz: 627d0d04d5ecea5e4c33ea0e59b15ac46fc458f76f179ac624d3519036865ad29267f629b1b3fda7592a50c846ea2cf06cc58a8f188a06caee44715268c18d07
7
+ data.tar.gz: 9742adef6879fbd08b00350674dced4b4886e476b45388d6d1a1afaaebba440153632e878649ff68beb223b158f365dd180b6db76e8463a13dbbeb4cdf8aa88d
@@ -1,9 +1,18 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Lint/SplatKeywordArguments:
5
+ Enabled: false
6
+
1
7
  Style/FrozenStringLiteralComment:
2
8
  Enabled: false
3
9
 
4
10
  Style/Documentation:
5
11
  Enabled: false
6
12
 
13
+ Style/SafeNavigation:
14
+ Enabled: false
15
+
7
16
  Metrics/LineLength:
8
17
  Enabled: false
9
18
 
@@ -3,9 +3,9 @@ language: ruby
3
3
  cache: bundler
4
4
 
5
5
  rvm:
6
- - 2.3.6
7
- - 2.4.3
8
6
  - 2.5.0
7
+ - 2.7.2
8
+ - 3.0.0
9
9
  - ruby-head
10
10
  - jruby-9.1.16.0
11
11
  - jruby-head
@@ -15,7 +15,7 @@ before_install:
15
15
 
16
16
  matrix:
17
17
  include:
18
- - rvm: 2.3.6
18
+ - rvm: 2.7.2
19
19
  script:
20
20
  - bundle exec danger
21
21
  allow_failures:
@@ -1,6 +1,34 @@
1
- ### 0.3.3 (Next)
2
-
1
+ ### 0.6.0 (Next)
3
2
  * Your contribution here.
3
+
4
+ ### 0.5.0 (12/28/2020)
5
+
6
+ * [#81](https://github.com/ashkan18/graphlient/pull/81): Make graphlient run on ruby 3.0 - [@Burgestrand](https://github.com/Burgestrand).
7
+ * [#79](https://github.com/ashkan18/graphlient/pull/79): Added client testing docs - [@GabrielDzul](https://github.com/GabrielDzul).
8
+
9
+ ### 0.4.0 (5/22/2020)
10
+
11
+ * [#72](https://github.com/ashkan18/graphlient/pull/72): Add http_options - [@neroleung](https://github.com/neroleung).
12
+ * [#71](https://github.com/ashkan18/graphlient/issues/70): Add `Graphlient::Errors::TimeoutError` - [@BenDrozdoff](https://github.com/BenDrozdoff).
13
+ * [#75](https://github.com/ashkan18/graphlient/pull/75): Support Faraday 1.x - [@jfhinchcliffe](https://github.com/jfhinchcliffe).
14
+ * [#78](https://github.com/ashkan18/graphlient/pull/78): Add description of timeout values - [@sap1enza](https://github.com/sap1enza).
15
+
16
+ ### 0.3.7 (11/14/2019)
17
+
18
+ * [#68](https://github.com/ashkan18/graphlient/pull/68): Add `Graphlient::Errors::ConnectionFailedError` - [@neroleung](https://github.com/neroleung).
19
+
20
+ ### 0.3.6 (07/23/2019)
21
+
22
+ * [#63](https://github.com/ashkan18/graphlient/pull/63): Remove unused method for attribute with typo - [@ashkan18](https://github.com/ashkan18).
23
+ * [#62](https://github.com/ashkan18/graphlient/pull/62): Fix typo preventing access to response object on error - [@jmondo](https://github.com/jmondo).
24
+
25
+ ### 0.3.4 (01/31/2019)
26
+
27
+ * [#56](https://github.com/ashkan18/graphlient/pull/56): Remove safe navigation usage to retain support for Ruby 2.2 - [@avinoth](https://github.com/avinoth).
28
+ * [#57](https://github.com/ashkan18/graphlient/pull/57): Add support for parsing queries from a String - [@ateamlunchbox](https://github.com/ateamlunchbox).
29
+
30
+ ### 0.3.3 (09/23/2018)
31
+
4
32
  * [#50](https://github.com/ashkan18/graphlient/pull/50): More detailed error responses - [@ashkan18](https://github.com/ashkan18).
5
33
 
6
34
  ### 0.3.2 (07/03/2018)
data/Gemfile CHANGED
@@ -4,6 +4,10 @@ gemspec
4
4
 
5
5
  gem 'rake'
6
6
 
7
+ group :development, :test do
8
+ gem 'activesupport', '< 6'
9
+ end
10
+
7
11
  group :development do
8
12
  gem 'byebug', platform: :ruby
9
13
  gem 'danger-changelog', '~> 0.2.1'
@@ -11,7 +15,7 @@ group :development do
11
15
  end
12
16
 
13
17
  group :test do
14
- gem 'graphql'
18
+ gem 'graphql', '~> 1.9'
15
19
  gem 'graphql-errors'
16
20
  gem 'rack-parser'
17
21
  gem 'rack-test'
data/README.md CHANGED
@@ -15,16 +15,25 @@ gem 'graphlient'
15
15
 
16
16
  ## Usage
17
17
 
18
- Create a new instance of `Graphlient::Client` with a URL and optional headers.
18
+ Create a new instance of `Graphlient::Client` with a URL and optional headers/http_options.
19
19
 
20
20
  ```ruby
21
21
  client = Graphlient::Client.new('https://test-graphql.biz/graphql',
22
22
  headers: {
23
23
  'Authorization' => 'Bearer 123'
24
+ },
25
+ http_options: {
26
+ read_timeout: 20,
27
+ write_timeout: 30
24
28
  }
25
29
  )
26
30
  ```
27
31
 
32
+ | http_options | default | type |
33
+ |---------------|---------|---------|
34
+ | read_timeout | nil | seconds |
35
+ | write_timeout | nil | seconds |
36
+
28
37
  The schema is available automatically via `.schema`.
29
38
 
30
39
  ```ruby
@@ -126,6 +135,9 @@ Unlike graphql-client, Graphlient will always raise an exception unless the quer
126
135
  * [Graphlient::Errors::ServerError](lib/graphlient/errors/server_error.rb): all transport errors raised by HTTP Adapters. You can access `inner_exception`, `status_code` and `response` on these errors to get more details on what went wrong
127
136
  * [Graphlient::Errors::FaradayServerError](lib/graphlient/errors/faraday_server_error.rb): this inherits from `ServerError` ☝️, we recommend using `ServerError` to rescue these
128
137
  * [Graphlient::Errors::HttpServerError](lib/graphlient/errors/http_server_error.rb): this inherits from `ServerError` ☝️, we recommend using `ServerError` to rescue these
138
+ * [Graphlient::Errors::ConnectionFailedError](lib/graphlient/errors/connection_failed_error.rb): this inherits from `ServerError` ☝️, we recommend using `ServerError` to rescue these
139
+ * [Graphlient::Errors::TimeoutError](lib/graphlient/errors/timeout_error.rb): this inherits from `ServerError` ☝️, we recommend using `ServerError` to rescue these
140
+ * [Graphlient::Errors::HttpOptionsError](lib/graphlient/errors/http_options_error.rb): all NoMethodError raised by HTTP Adapters when given options in `http_options` are invalid
129
141
 
130
142
 
131
143
  All errors inherit from `Graphlient::Errors::Error` if you need to handle them in bulk.
@@ -208,6 +220,23 @@ end
208
220
  client.execute query, ids: [42]
209
221
  ```
210
222
 
223
+ Or pass in a string instead of a block:
224
+
225
+ ```ruby
226
+ # parse a query, returns a GraphQL::Client::OperationDefinition
227
+ query = client.parse <<~GRAPHQL
228
+ query($some_id: Int) {
229
+ invoice(id: $some_id) {
230
+ id
231
+ feeInCents
232
+ }
233
+ }
234
+ GRAPHQL
235
+
236
+ # execute a query, returns a GraphQL::Client::Response
237
+ client.execute query, ids: [42]
238
+ ```
239
+
211
240
  ### Dynamic vs. Static Queries
212
241
 
213
242
  Graphlient uses [graphql-client](https://github.com/github/graphql-client), which [recommends](https://github.com/github/graphql-client/blob/master/guides/dynamic-query-error.md) building queries as static module members along with dynamic variables during execution. This can be accomplished with graphlient the same way.
@@ -316,7 +345,7 @@ describe App do
316
345
  Graphlient::Client.new('http://test-graphql.biz/graphql') do |client|
317
346
  client.http do |h|
318
347
  h.connection do |c|
319
- c.use Faraday::Adapter::Rack, app
348
+ c.adapter Faraday::Adapter::Rack, app
320
349
  end
321
350
  end
322
351
  end
@@ -360,6 +389,49 @@ describe App do
360
389
  end
361
390
  ```
362
391
 
392
+ In order to stub the response to actual queries, [dump the schema into a JSON file](#schema-storing-and-loading-on-disk) and specify it via schema_path as follows.
393
+
394
+ ```ruby
395
+ describe App do
396
+ let(:url) { 'http://graph.biz/graphql' }
397
+ let(:client) { Graphlient::Client.new(url, schema_path: 'spec/support/fixtures/invoice_api.json') }
398
+ let(:query) do
399
+ <<~GRAPHQL
400
+ query{
401
+ invoice(id: 42) {
402
+ id
403
+ feeInCents
404
+ }
405
+ }
406
+ GRAPHQL
407
+ end
408
+ let(:json_response) do
409
+ {
410
+ 'data' => {
411
+ 'invoice' => {
412
+ 'id' => '42',
413
+ 'feeInCents' => 2000
414
+ }
415
+ }
416
+ }.to_json
417
+ end
418
+
419
+ before do
420
+ stub_request(:post, url).to_return(
421
+ status: 200,
422
+ body: json_response
423
+ )
424
+ end
425
+
426
+ it 'returns invoice fees' do
427
+ response = client.query(query)
428
+ expect(response.data).to be_truthy
429
+ expect(response.data.invoice.id).to eq('42')
430
+ expect(response.data.invoice.fee_in_cents).to eq(2000)
431
+ end
432
+ end
433
+ ```
434
+
363
435
  ## License
364
436
 
365
437
  MIT License, see [LICENSE](LICENSE)
@@ -21,6 +21,8 @@ Change next release in [CHANGELOG.md](CHANGELOG.md) to the new version.
21
21
 
22
22
  Remove the line with "Your contribution here.", since there will be no more contributions to this release.
23
23
 
24
+ Update the version in `lib/graphlient/version.rb`.
25
+
24
26
  Commit your changes.
25
27
 
26
28
  ```
@@ -0,0 +1,23 @@
1
+ Upgrading Graphlient
2
+ ===========================
3
+
4
+ ### Upgrading to >= 0.4.0
5
+
6
+ #### Requires Faraday >= 1.0
7
+
8
+ See [#75](https://github.com/ashkan18/graphlient/pull/75).
9
+
10
+ #### Changes in error handling of connection refused error
11
+
12
+ When the GraphQL request was failing, we were receiving a `Faraday::ServerError`. After 0.4.0, Graphlient
13
+ will return `Graphlient::Errors::FaradayServerError` instead.
14
+
15
+ ### Upgrading to >= 0.3.7
16
+
17
+ #### Changes in error handling of connection refused error
18
+
19
+ Prior to 0.3.7, Graphlient would return `NoMethodError: undefined method []' for nil:NilClass` error if connection is
20
+ refused/failed when connecting to a remote host. After 0.3.7, Graphlient will return a new
21
+ `Graphlient::Errors::ConnectionFailedError` instead.
22
+
23
+ See [#68](https://github.com/ashkan18/graphlient/pull/68) for more information.
@@ -14,7 +14,7 @@ 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'
17
+ s.add_dependency 'faraday', '>= 1.0'
18
18
  s.add_dependency 'faraday_middleware'
19
19
  s.add_dependency 'graphql-client'
20
20
  end
@@ -14,9 +14,27 @@ module Graphlient
14
14
  options[:headers] if options
15
15
  end
16
16
 
17
+ def http_options
18
+ return {} unless options
19
+
20
+ options[:http_options] || {}
21
+ end
22
+
17
23
  def execute(*)
18
24
  raise NotImplementedError
19
25
  end
26
+
27
+ private
28
+
29
+ def configure_http_options(client_options)
30
+ http_options.each do |k, v|
31
+ begin
32
+ client_options.send("#{k}=", v)
33
+ rescue NoMethodError => e
34
+ raise Graphlient::Errors::HttpOptionsError, e.message
35
+ end
36
+ end
37
+ end
20
38
  end
21
39
  end
22
40
  end
@@ -15,8 +15,14 @@ module Graphlient
15
15
  }.to_json
16
16
  end
17
17
  response.body
18
+ rescue Faraday::ConnectionFailed => e
19
+ raise Graphlient::Errors::ConnectionFailedError, e
20
+ rescue Faraday::TimeoutError => e
21
+ raise Graphlient::Errors::TimeoutError, e
18
22
  rescue Faraday::ClientError => e
19
23
  raise Graphlient::Errors::FaradayServerError, e
24
+ rescue Faraday::ServerError => e
25
+ raise Graphlient::Errors::FaradayServerError, e
20
26
  end
21
27
 
22
28
  def connection
@@ -24,10 +30,13 @@ module Graphlient
24
30
  c.use Faraday::Response::RaiseError
25
31
  c.request :json
26
32
  c.response :json
33
+
34
+ configure_http_options(c.options)
35
+
27
36
  if block_given?
28
37
  yield c
29
38
  else
30
- c.use Faraday::Adapter::NetHttp
39
+ c.adapter Faraday::Adapter::NetHttp
31
40
  end
32
41
  end
33
42
  end
@@ -9,7 +9,7 @@ module Graphlient
9
9
 
10
10
  request['Accept'] = 'application/json'
11
11
  request['Content-Type'] = 'application/json'
12
- headers&.each { |name, value| request[name] = value }
12
+ headers && headers.each { |name, value| request[name] = value }
13
13
 
14
14
  body = {}
15
15
  body['query'] = document.to_query_string
@@ -29,6 +29,8 @@ module Graphlient
29
29
  def connection
30
30
  Net::HTTP.new(uri.host, uri.port).tap do |client|
31
31
  client.use_ssl = uri.scheme == 'https'
32
+
33
+ configure_http_options(client)
32
34
  end
33
35
  end
34
36
  end
@@ -8,8 +8,8 @@ module Graphlient
8
8
  yield self if block_given?
9
9
  end
10
10
 
11
- def parse(&block)
12
- query_str = Graphlient::Query.new do
11
+ def parse(query_str = nil, &block)
12
+ query_str ||= Graphlient::Query.new do
13
13
  instance_eval(&block)
14
14
  end
15
15
  client.parse(query_str.to_s)
@@ -22,11 +22,11 @@ module Graphlient
22
22
  query_params[:context] = @options if @options
23
23
  query_params[:variables] = variables if variables
24
24
  query = client.parse(query) if query.is_a?(String)
25
- rc = client.query(query, query_params)
25
+ rc = client.query(query, **query_params)
26
26
  raise Graphlient::Errors::GraphQLError, rc if rc.errors.any?
27
27
  # see https://github.com/github/graphql-client/pull/132
28
28
  # see https://github.com/exAspArk/graphql-errors/issues/2
29
- raise Graphlient::Errors::ExecutionError, rc if rc.data&.errors && rc.data.errors.any?
29
+ raise Graphlient::Errors::ExecutionError, rc if errors_in_result?(rc)
30
30
  rc
31
31
  rescue GraphQL::Client::Error => e
32
32
  raise Graphlient::Errors::ClientError, e.message
@@ -45,7 +45,9 @@ module Graphlient
45
45
  end
46
46
 
47
47
  def http(&block)
48
- @http ||= http_adapter_class.new(@url, headers: @options[:headers], &block)
48
+ adapter_options = { headers: @options[:headers], http_options: @options[:http_options] }
49
+
50
+ @http ||= http_adapter_class.new(@url, adapter_options, &block)
49
51
  end
50
52
 
51
53
  def schema
@@ -63,5 +65,9 @@ module Graphlient
63
65
  client.allow_dynamic_queries = @options.key?(:allow_dynamic_queries) ? options[:allow_dynamic_queries] : true
64
66
  end
65
67
  end
68
+
69
+ def errors_in_result?(response)
70
+ response.data && response.data.errors && response.data.errors.any?
71
+ end
66
72
  end
67
73
  end
@@ -4,4 +4,7 @@ require_relative 'errors/server_error'
4
4
  require_relative 'errors/graphql_error'
5
5
  require_relative 'errors/execution_error'
6
6
  require_relative 'errors/faraday_server_error'
7
+ require_relative 'errors/http_options_error'
7
8
  require_relative 'errors/http_server_error'
9
+ require_relative 'errors/connection_failed_error'
10
+ require_relative 'errors/timeout_error'
@@ -0,0 +1,6 @@
1
+ module Graphlient
2
+ module Errors
3
+ class ConnectionFailedError < ServerError
4
+ end
5
+ end
6
+ end
@@ -1,7 +1,7 @@
1
1
  module Graphlient
2
2
  module Errors
3
3
  class GraphQLError < Error
4
- attr_reader :responsee
4
+ attr_reader :response
5
5
  def initialize(response)
6
6
  super('the server responded with a GraphQL error')
7
7
  @response = response
@@ -0,0 +1,6 @@
1
+ module Graphlient
2
+ module Errors
3
+ class HttpOptionsError < Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Graphlient
2
+ module Errors
3
+ class TimeoutError < Error
4
+ end
5
+ end
6
+ end
@@ -1,3 +1,3 @@
1
1
  module Graphlient
2
- VERSION = '0.3.3'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -8,29 +8,32 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
8
8
  Graphlient::Client.new('http://example.com/graphql') do |client|
9
9
  client.http do |h|
10
10
  h.connection do |c|
11
- c.use Faraday::Adapter::Rack, app
11
+ c.adapter Faraday::Adapter::Rack, app
12
12
  end
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
17
  it 'inserts a middleware into the connection' do
18
+ expect(client.http.connection.adapter).to eq Faraday::Adapter::Rack
18
19
  expect(client.http.connection.builder.handlers).to eq(
19
20
  [
20
21
  Faraday::Response::RaiseError,
21
22
  FaradayMiddleware::EncodeJson,
22
- FaradayMiddleware::ParseJson,
23
- Faraday::Adapter::Rack
23
+ FaradayMiddleware::ParseJson
24
24
  ]
25
25
  )
26
26
  end
27
27
  end
28
28
 
29
- context 'with custom url and headers' do
29
+ context 'with custom url, headers and http_options' do
30
30
  let(:url) { 'http://example.com/graphql' }
31
31
  let(:headers) { { 'Foo' => 'bar' } }
32
+ let(:http_options) { { timeout: timeout, write_timeout: write_timeout } }
33
+ let(:timeout) { 123 }
34
+ let(:write_timeout) { 234 }
32
35
  let(:client) do
33
- Graphlient::Client.new(url, headers: headers)
36
+ Graphlient::Client.new(url, headers: headers, http_options: http_options)
34
37
  end
35
38
 
36
39
  it 'sets url' do
@@ -40,6 +43,19 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
40
43
  it 'sets headers' do
41
44
  expect(client.http.headers).to eq headers
42
45
  end
46
+
47
+ it 'sets http_options' do
48
+ expect(client.http.connection.options.timeout).to eq(timeout)
49
+ expect(client.http.connection.options.write_timeout).to eq(write_timeout)
50
+ end
51
+
52
+ context 'when http_options contains invalid option' do
53
+ let(:http_options) { { an_invalid_option: 'an invalid option' } }
54
+
55
+ it 'raises Graphlient::Errors::HttpOptionsError' do
56
+ expect { client.http.connection }.to raise_error(Graphlient::Errors::HttpOptionsError)
57
+ end
58
+ end
43
59
  end
44
60
 
45
61
  context 'default' do
@@ -57,4 +73,40 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
57
73
  expect(client.schema).to be_a Graphlient::Schema
58
74
  end
59
75
  end
76
+
77
+ context 'Failed to open TCP connection error' do
78
+ let(:url) { 'http://example.com/graphql' }
79
+ let(:client) { Graphlient::Client.new(url) }
80
+ let(:error_message) do
81
+ 'Failed to open TCP connection to localhost:3000 (Connection refused - connect(2) for "localhost" port 3000)'
82
+ end
83
+
84
+ before do
85
+ wrapped_error = Errno::ECONNREFUSED.new(error_message)
86
+ error = Faraday::ConnectionFailed.new(wrapped_error)
87
+
88
+ stub_request(:post, url).to_raise(error)
89
+ end
90
+
91
+ specify do
92
+ expected_error_message = "Connection refused - #{error_message}"
93
+
94
+ expect { client.schema }.to raise_error(Graphlient::Errors::ConnectionFailedError, expected_error_message)
95
+ end
96
+ end
97
+
98
+ context 'Faraday Timeout Error' do
99
+ let(:url) { 'http://example.com/graphql' }
100
+ let(:client) { Graphlient::Client.new(url) }
101
+ let(:error_message) { 'Failed to Connect' }
102
+
103
+ before do
104
+ stub_request(:post, url).to_raise(Faraday::TimeoutError.new(Net::ReadTimeout.new(error_message)))
105
+ end
106
+ it 'raises a Graphlient Timeout' do
107
+ expect { client.schema }.to raise_error(Graphlient::Errors::TimeoutError) { |error|
108
+ expect(error.message).to include(error_message)
109
+ }
110
+ end
111
+ end
60
112
  end