graphlient 0.6.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: 2b777ec75d94d228faa748cadb28c1687b16a377892138a9fc8d1048773b8853
4
- data.tar.gz: a3bc9f948ffa5c4fe6368282834b7cd4e7addc00b7d1c90ced575ce41e8a8b3a
3
+ metadata.gz: ed5f47ad98345af440481f9dca800767524807bc667eace999d7ba36826e59fa
4
+ data.tar.gz: 22ec20f5b725b3bb85bc9c8e8371693824f7fd85b2db43336ce7f6a6be31543f
5
5
  SHA512:
6
- metadata.gz: fc0080c0fab50ac5ecee6815fb24e6b216cba32558d010ebd3d9661581b55f3b3fca8b70e11f0e61f96eb471931645c12b3a3b8c2361909da31a15c650ab6bcb
7
- data.tar.gz: feb39198706b8b9650da8f6f35f080744df668420d948f2b7d69d84dd3b812301542d5735d1a69f77d865706e5853703861fe440a1ab47ea2cfef3b91712f794
6
+ metadata.gz: 1c5ddbaafe24dfbdd6e99535bedb7a021eba55a956b4b716661c9c8778018a96118afc5a6def029aad14da883de8d47a747b4a85ead2cee0868d5ddcfb298359
7
+ data.tar.gz: 3fd8b40976687fd83b00b865f62d514a87571de0bf68015486328d526a2d9cc76a8c4454a5d78f86acba6480860ac1abde3ff2edda1e92c26b03c58f60b067e2
@@ -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.
@@ -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
@@ -5,6 +5,8 @@ on: pull_request
5
5
  jobs:
6
6
  danger:
7
7
  runs-on: ubuntu-latest
8
+ env:
9
+ BUNDLE_GEMFILE: ${{ github.workspace }}/Gemfile.danger
8
10
  steps:
9
11
  - uses: actions/checkout@v3
10
12
  with:
@@ -16,5 +18,5 @@ jobs:
16
18
  bundler-cache: true
17
19
  - run: |
18
20
  # the personal token is public, this is ok, base64 encode to avoid tripping Github
19
- TOKEN=$(echo -n NWY1ZmM5MzEyMzNlYWY4OTZiOGU3MmI3MWQ3Mzk0MzgxMWE4OGVmYwo= | base64 --decode)
21
+ TOKEN=$(echo -n Z2hwX0xNQ3VmanBFeTBvYkZVTWh6NVNqVFFBOEUxU25abzBqRUVuaAo= | base64 --decode)
20
22
  DANGER_GITHUB_API_TOKEN=$TOKEN bundle exec danger --verbose
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### (Next)
2
+ * Your contribution here.
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
+
10
+ ### 0.7.0 (2022/10/11)
11
+ * [#98](https://github.com/ashkan18/graphlient/pull/98): Bring back danger checks and improve them - [@ashkan18](https://github.com/ashkan18).
12
+ * [#94](https://github.com/ashkan18/graphlient/pull/94): Enabled fragments - [@rellampec](https://github.com/rellampec).
13
+ * [#95](https://github.com/ashkan18/graphlient/pull/95): Upgrade faraday dependency to version 2 - [@kirillkaiumov](https://github.com/kirillkaiumov).
14
+
1
15
  ### 0.6.0 (2022/06/11)
2
16
 
3
17
  * [#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
- changelog.check
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
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'danger-changelog', '~> 0.6.0'
5
+ end
data/README.md CHANGED
@@ -5,6 +5,22 @@
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
+ - [Preloading Schema Once](#preloading-schema-once)
14
+ - [Error Handling](#error-handling)
15
+ - [Executing Parameterized Queries and Mutations](#executing-parameterized-queries-and-mutations)
16
+ - [Parse and Execute Queries Separately](#parse-and-execute-queries-separately)
17
+ - [Dynamic vs. Static Queries](#dynamic-vs-static-queries)
18
+ - [Generate Queries with Graphlient::Query](#generate-queries-with-graphlientquery)
19
+ - [Create API Client Classes with Graphlient::Extension::Query](#create-api-client-classes-with-graphlientextensionquery)
20
+ - [Swapping the HTTP Stack](#swapping-the-http-stack)
21
+ - [Testing with Graphlient and RSpec](#testing-with-graphlient-and-rspec)
22
+ - [License](#license)
23
+
8
24
  ## Installation
9
25
 
10
26
  Add the following line to your Gemfile.
@@ -125,6 +141,30 @@ client = Client.new(url, schema_path: 'config/your_graphql_schema.json')
125
141
  client.schema.dump! # you only need to call this when graphql schema changes
126
142
  ```
127
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
+
128
168
  ### Error Handling
129
169
 
130
170
  Unlike graphql-client, Graphlient will always raise an exception unless the query has succeeded.
@@ -300,6 +340,62 @@ query.to_s
300
340
  # "\nquery {\n invoice(id: 10){\n line_items\n }\n }\n"
301
341
  ```
302
342
 
343
+ ### Use of Fragments
344
+
345
+ [Fragments](https://github.com/github/graphql-client#defining-queries) should be referred by constant:
346
+
347
+ ```ruby
348
+ module Fragments
349
+ Invoice = client.parse <<~'GRAPHQL'
350
+ fragment on Invoice {
351
+ id
352
+ feeInCents
353
+ }
354
+ GRAPHQL
355
+ end
356
+ ```
357
+
358
+ `Graphlient` offers the syntax below to refer to the original constant:
359
+ * Triple underscore `___` to refer to the fragment
360
+ * Double underscore `__` for namespace separator
361
+
362
+ In this example, `Fragments::Invoice` would be referred as follows:
363
+
364
+ ```ruby
365
+ invoice_query = client.parse do
366
+ query do
367
+ invoice(id: 10) do
368
+ id
369
+ ___Fragments__Invoice
370
+ end
371
+ end
372
+ end
373
+ ```
374
+
375
+ The wrapped response only allows access to fields that have been explicitly asked for.
376
+ 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).
377
+
378
+ ```ruby
379
+ response = client.execute(invoice_query)
380
+ result = response.data.invoice
381
+ result.to_h
382
+ # {"id" => 10, "feeInCents"=> 20000}
383
+ result.id
384
+ # 10
385
+ result.fee_in_cents
386
+ # raises GraphQL::Client::ImplicitlyFetchedFieldError
387
+ ```
388
+
389
+ `feeInCents` cannot be fetched directly from the main query, but from the fragment as shown below:
390
+
391
+ ```ruby
392
+ invoice = Fragments::Invoice.new(result)
393
+ invoice.id
394
+ # 10
395
+ invoice.fee_in_cents
396
+ # 20000
397
+ ```
398
+
303
399
  ### Create API Client Classes with Graphlient::Extension::Query
304
400
 
305
401
  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', '>= 1.0'
18
- s.add_dependency 'faraday_middleware'
17
+ s.add_dependency 'faraday', '~> 2.0'
19
18
  s.add_dependency 'graphql-client'
20
19
  end
@@ -1,5 +1,5 @@
1
1
  require 'faraday'
2
- require 'faraday_middleware'
2
+ require 'json'
3
3
 
4
4
  module Graphlient
5
5
  module Adapters
@@ -14,7 +14,8 @@ module Graphlient
14
14
  variables: variables
15
15
  }.to_json
16
16
  end
17
- response.body
17
+
18
+ parse_body(response.body)
18
19
  rescue Faraday::ConnectionFailed => e
19
20
  raise Graphlient::Errors::ConnectionFailedError, e
20
21
  rescue Faraday::TimeoutError => e
@@ -40,6 +41,38 @@ module Graphlient
40
41
  end
41
42
  end
42
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
43
76
  end
44
77
  end
45
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
@@ -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
- instance_eval(&block)
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
- instance_eval(&block)
71
+ evaluate(&block)
53
72
  @query_str << '}'
54
73
  @indents -= 1
55
74
  end
@@ -1,3 +1,3 @@
1
1
  module Graphlient
2
- VERSION = '0.6.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -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
- FaradayMiddleware::EncodeJson,
23
- FaradayMiddleware::ParseJson
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
 
@@ -74,6 +75,61 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
74
75
  end
75
76
  end
76
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
+
77
133
  context 'Failed to open TCP connection error' do
78
134
  let(:url) { 'http://example.com/graphql' }
79
135
  let(:client) { Graphlient::Client.new(url) }
@@ -90,7 +146,6 @@ describe Graphlient::Adapters::HTTP::FaradayAdapter do
90
146
 
91
147
  specify do
92
148
  expected_error_message = "Connection refused - #{error_message}"
93
-
94
149
  expect { client.schema }.to raise_error(Graphlient::Errors::ConnectionFailedError, expected_error_message)
95
150
  end
96
151
  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
- .to_return(body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json)
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(status: 500, body: { errors: [{ message: 'test message', extensions: { code: 'SOMETHING', timestamp: Time.now } }] }.to_json)
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
@@ -41,5 +51,25 @@ describe Graphlient::Client do
41
51
  expect(client.schema.path).to eq 'config/schema.json'
42
52
  end
43
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
44
74
  end
45
75
  end
@@ -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(body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json)
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
@@ -27,7 +27,8 @@ describe 'App' do
27
27
  before do
28
28
  stub_request(:post, url).to_return(
29
29
  status: 200,
30
- body: json_response
30
+ body: json_response,
31
+ headers: { 'Content-Type' => 'application/json' }
31
32
  )
32
33
  end
33
34
 
data/spec/spec_helper.rb CHANGED
@@ -7,6 +7,7 @@ require 'byebug' if RUBY_ENGINE != 'jruby'
7
7
  require 'rack/test'
8
8
  require 'webmock/rspec'
9
9
  require 'vcr'
10
+ require 'faraday/rack'
10
11
 
11
12
  Dir[File.join(File.dirname(__FILE__), 'support', '**/*.rb')].each do |file|
12
13
  require file
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.6.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-06-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
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
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.3
134
+ rubygems_version: 3.3.7
146
135
  signing_key:
147
136
  specification_version: 4
148
137
  summary: A friendlier Ruby client for consuming GraphQL-based APIs.