graphlient 0.0.5 → 0.0.6
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/.gitignore +2 -1
- data/.rubocop_todo.yml +32 -17
- data/.travis.yml +8 -2
- data/CHANGELOG.md +11 -0
- data/Dangerfile +1 -0
- data/Gemfile +5 -0
- data/README.md +200 -26
- data/RELEASING.md +1 -1
- data/Rakefile +1 -1
- data/graphlient.gemspec +3 -0
- data/lib/graphlient.rb +0 -5
- data/lib/graphlient/adapters/faraday_adapter.rb +43 -0
- data/lib/graphlient/client.rb +35 -20
- data/lib/graphlient/errors.rb +2 -1
- data/lib/graphlient/errors/client.rb +6 -0
- data/lib/graphlient/errors/error.rb +7 -0
- data/lib/graphlient/errors/server.rb +6 -0
- data/lib/graphlient/query.rb +13 -5
- data/lib/graphlient/version.rb +1 -1
- data/spec/graphlient/adapters/faraday_adapter_spec.rb +44 -0
- data/spec/graphlient/client_query_spec.rb +158 -0
- data/spec/graphlient/client_schema_spec.rb +19 -0
- data/spec/graphlient/extensions/query_spec.rb +6 -4
- data/spec/graphlient/query_spec.rb +72 -25
- data/spec/graphlient/static_client_query_spec.rb +39 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/context/dummy_client.rb +26 -0
- data/spec/support/dummy_app.rb +25 -0
- data/spec/support/dummy_schema.rb +9 -0
- data/spec/support/mutations/create_invoice_mutation.rb +16 -0
- data/spec/support/mutations/mutation.rb +7 -0
- data/spec/support/queries/query.rb +16 -0
- data/spec/support/types/invoice_type.rb +6 -0
- metadata +61 -8
- data/.byebug_history +0 -23
- data/lib/graphlient/config.rb +0 -21
- data/lib/graphlient/errors/http.rb +0 -12
- data/spec/graphlient/client_spec.rb +0 -42
data/graphlient.gemspec
CHANGED
@@ -14,4 +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 = 'Ruby Gem for consuming GraphQL endpoints'
|
17
|
+
s.add_dependency 'graphql-client'
|
18
|
+
s.add_dependency 'faraday'
|
19
|
+
s.add_dependency 'faraday_middleware'
|
17
20
|
end
|
data/lib/graphlient.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
module Graphlient
|
5
|
+
module Adapters
|
6
|
+
class FaradayAdapter
|
7
|
+
attr_accessor :url, :headers
|
8
|
+
|
9
|
+
def initialize(url, headers:, &_block)
|
10
|
+
@url = url
|
11
|
+
@headers = headers.dup if headers
|
12
|
+
yield self if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(document:, operation_name:, variables:, context:)
|
16
|
+
response = connection.post do |req|
|
17
|
+
req.headers.merge!(context[:headers] || {})
|
18
|
+
req.body = {
|
19
|
+
query: document.to_query_string,
|
20
|
+
operationName: operation_name,
|
21
|
+
variables: variables.to_json
|
22
|
+
}.to_json
|
23
|
+
end
|
24
|
+
response.body
|
25
|
+
rescue Faraday::ClientError => e
|
26
|
+
raise Graphlient::Errors::Server.new(e.message, e)
|
27
|
+
end
|
28
|
+
|
29
|
+
def connection
|
30
|
+
@connection ||= Faraday.new(url: url, headers: headers) do |c|
|
31
|
+
c.use Faraday::Response::RaiseError
|
32
|
+
c.request :json
|
33
|
+
c.response :json
|
34
|
+
if block_given?
|
35
|
+
yield c
|
36
|
+
else
|
37
|
+
c.use Faraday::Adapter::NetHttp
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/graphlient/client.rb
CHANGED
@@ -1,37 +1,52 @@
|
|
1
|
+
require 'graphql/client'
|
2
|
+
require 'graphlient/adapters/faraday_adapter'
|
3
|
+
|
1
4
|
module Graphlient
|
2
5
|
class Client
|
3
|
-
|
4
|
-
attr_reader :options
|
6
|
+
attr_accessor :uri, :options
|
5
7
|
|
6
|
-
def initialize(url, options = {})
|
7
|
-
@
|
8
|
+
def initialize(url, options = {}, &_block)
|
9
|
+
@url = url
|
8
10
|
@options = options.dup
|
11
|
+
yield self if block_given?
|
9
12
|
end
|
10
13
|
|
11
|
-
def
|
12
|
-
|
14
|
+
def parse(&block)
|
15
|
+
query_str = Graphlient::Query.new do
|
13
16
|
instance_eval(&block)
|
14
17
|
end
|
15
|
-
|
16
|
-
raise Graphlient::Errors::HTTP.new(response.message, response) unless response.is_a? Net::HTTPSuccess
|
17
|
-
parse(response.body)
|
18
|
+
client.parse(query_str.to_s)
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
21
|
+
def execute(query, variables = nil)
|
22
|
+
query_params = {}
|
23
|
+
query_params[:context] = @options if @options
|
24
|
+
query_params[:variables] = variables if variables
|
25
|
+
client.query(query, query_params)
|
26
|
+
rescue GraphQL::Client::Error => e
|
27
|
+
raise Graphlient::Errors::Client.new(e.message, e)
|
22
28
|
end
|
23
29
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
def query(variables = nil, &block)
|
31
|
+
execute(parse(&block), variables)
|
32
|
+
rescue GraphQL::Client::Error => e
|
33
|
+
raise Graphlient::Errors::Client.new(e.message, e)
|
34
|
+
end
|
35
|
+
|
36
|
+
def http(&block)
|
37
|
+
@http ||= Adapters::FaradayAdapter.new(@url, headers: @options[:headers], &block)
|
31
38
|
end
|
32
39
|
|
33
|
-
def
|
34
|
-
|
40
|
+
def schema
|
41
|
+
@schema ||= GraphQL::Client.load_schema(http)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def client
|
47
|
+
@client ||= GraphQL::Client.new(schema: schema, execute: http).tap do |client|
|
48
|
+
client.allow_dynamic_queries = @options.key?(:allow_dynamic_queries) ? options[:allow_dynamic_queries] : true
|
49
|
+
end
|
35
50
|
end
|
36
51
|
end
|
37
52
|
end
|
data/lib/graphlient/errors.rb
CHANGED
data/lib/graphlient/query.rb
CHANGED
@@ -17,7 +17,7 @@ module Graphlient
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_s
|
20
|
-
|
20
|
+
query_str.strip
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
@@ -26,7 +26,7 @@ module Graphlient
|
|
26
26
|
# add field
|
27
27
|
@query_str << "\n#{indent}#{query_field}"
|
28
28
|
# add filter
|
29
|
-
@query_str << "(#{get_args_str(args)})" if args
|
29
|
+
@query_str << "(#{get_args_str(args)})" if find_hash_arg(args)
|
30
30
|
|
31
31
|
if block_given?
|
32
32
|
@indents += 1
|
@@ -44,9 +44,15 @@ module Graphlient
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def get_args_str(args)
|
47
|
-
args
|
48
|
-
|
49
|
-
|
47
|
+
hash_args_str(find_hash_arg(args))
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_hash_arg(args)
|
51
|
+
args.detect { |arg| arg.is_a? Hash }
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash_args_str(hash)
|
55
|
+
hash.map { |k, v| "#{k}: #{get_arg_value_str(v)}" }.join(', ')
|
50
56
|
end
|
51
57
|
|
52
58
|
def get_arg_value_str(value)
|
@@ -57,6 +63,8 @@ module Graphlient
|
|
57
63
|
value.to_s
|
58
64
|
when Array
|
59
65
|
"[#{value.map { |v| get_arg_value_str(v) }.join(', ')}]"
|
66
|
+
when Hash
|
67
|
+
"{ #{hash_args_str(value)} }"
|
60
68
|
else
|
61
69
|
value
|
62
70
|
end
|
data/lib/graphlient/version.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Graphlient::Adapters::FaradayAdapter do
|
4
|
+
let(:app) { Object.new }
|
5
|
+
|
6
|
+
context 'with a custom middleware' do
|
7
|
+
let(:client) do
|
8
|
+
Graphlient::Client.new('http://example.com/graphql') do |client|
|
9
|
+
client.http do |h|
|
10
|
+
h.connection do |c|
|
11
|
+
c.use Faraday::Adapter::Rack, app
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'inserts a middleware into the connection' do
|
18
|
+
expect(client.http.connection.builder.handlers).to eq(
|
19
|
+
[
|
20
|
+
Faraday::Response::RaiseError,
|
21
|
+
FaradayMiddleware::EncodeJson,
|
22
|
+
FaradayMiddleware::ParseJson,
|
23
|
+
Faraday::Adapter::Rack
|
24
|
+
]
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with custom url and headers' do
|
30
|
+
let(:url) { 'http://example.com/graphql' }
|
31
|
+
let(:headers) { { 'Foo' => 'bar' } }
|
32
|
+
let(:client) do
|
33
|
+
Graphlient::Client.new(url, headers: headers)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets url' do
|
37
|
+
expect(client.http.url).to eq url
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sets headers' do
|
41
|
+
expect(client.http.headers).to eq headers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Graphlient::Client do
|
4
|
+
include_context 'Dummy Client'
|
5
|
+
|
6
|
+
describe 'parse and execute' do
|
7
|
+
context 'non-parameterized query' do
|
8
|
+
let(:query) do
|
9
|
+
client.parse do
|
10
|
+
query do
|
11
|
+
invoices(ids: [10]) do
|
12
|
+
id
|
13
|
+
fee_in_cents
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it '#parse' do
|
20
|
+
expect(query).to be_a GraphQL::Client::OperationDefinition
|
21
|
+
end
|
22
|
+
|
23
|
+
it '#execute' do
|
24
|
+
response = client.execute(query)
|
25
|
+
invoices = response.data.invoices
|
26
|
+
expect(invoices.first.id).to eq 10
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'parameterized query' do
|
31
|
+
let(:query) do
|
32
|
+
client.parse do
|
33
|
+
query(:$ids => :'[Int]') do
|
34
|
+
invoices(ids: :$ids) do
|
35
|
+
id
|
36
|
+
fee_in_cents
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it '#parse' do
|
43
|
+
expect(query).to be_a GraphQL::Client::OperationDefinition
|
44
|
+
end
|
45
|
+
|
46
|
+
it '#execute' do
|
47
|
+
response = client.execute(query, ids: [42])
|
48
|
+
invoices = response.data.invoices
|
49
|
+
expect(invoices.first.id).to eq 42
|
50
|
+
expect(invoices.first.fee_in_cents).to eq 20_000
|
51
|
+
end
|
52
|
+
|
53
|
+
it '#execute without variables' do
|
54
|
+
response = client.execute(query)
|
55
|
+
invoices = response.data.invoices
|
56
|
+
expect(invoices).to eq([])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#query' do
|
62
|
+
context 'non-parameterized query' do
|
63
|
+
it 'fails client-side on invalid schema' do
|
64
|
+
expect do
|
65
|
+
client.query do
|
66
|
+
query do
|
67
|
+
invoice(id: 10) do
|
68
|
+
id
|
69
|
+
fee_in_cents
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end.to raise_error Graphlient::Errors::Client do |e|
|
74
|
+
expect(e.to_s).to eq "Field 'invoice' doesn't exist on type 'Query'"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns a response from a query' do
|
79
|
+
response = client.query do
|
80
|
+
query do
|
81
|
+
invoices(ids: [10]) do
|
82
|
+
id
|
83
|
+
fee_in_cents
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
invoices = response.data.invoices
|
89
|
+
expect(invoices.first.id).to eq 10
|
90
|
+
expect(invoices.first.fee_in_cents).to eq 20_000
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns a response from a mutation' do
|
94
|
+
response = client.query do
|
95
|
+
mutation do
|
96
|
+
createInvoice(input: { fee_in_cents: 12_345 }) do
|
97
|
+
id
|
98
|
+
fee_in_cents
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
invoice = response.data.create_invoice.first
|
104
|
+
expect(invoice.id).to eq 1231
|
105
|
+
expect(invoice.fee_in_cents).to eq 12_345
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'parameterized query' do
|
110
|
+
it 'fails when missing input' do
|
111
|
+
response = client.query do
|
112
|
+
mutation('$input' => :createInvoiceInput!) do
|
113
|
+
createInvoice(input: :$input) do
|
114
|
+
id
|
115
|
+
fee_in_cents
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
expect(response.errors.messages['data']).to eq(
|
121
|
+
[
|
122
|
+
'Variable input of type createInvoiceInput! was provided invalid value'
|
123
|
+
]
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns a response from a query' do
|
128
|
+
response = client.query(ids: [42]) do
|
129
|
+
query(:$ids => :'[Int]') do
|
130
|
+
invoices(ids: :$ids) do
|
131
|
+
id
|
132
|
+
fee_in_cents
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
invoices = response.data.invoices
|
138
|
+
expect(invoices.first.id).to eq 42
|
139
|
+
expect(invoices.first.fee_in_cents).to eq 20_000
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'executes the mutation' do
|
143
|
+
response = client.query(input: { fee_in_cents: 12_345 }) do
|
144
|
+
mutation(:$input => :createInvoiceInput!) do
|
145
|
+
createInvoice(input: :$input) do
|
146
|
+
id
|
147
|
+
fee_in_cents
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
invoice = response.data.create_invoice.first
|
153
|
+
expect(invoice.id).to eq 1231
|
154
|
+
expect(invoice.fee_in_cents).to eq 12_345
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Graphlient::Client do
|
4
|
+
let(:client) { Graphlient::Client.new('http://graph.biz/graphql') }
|
5
|
+
|
6
|
+
describe '#schema' do
|
7
|
+
before do
|
8
|
+
stub_request(:post, 'http://graph.biz/graphql').to_return(status: 500)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'fails with an exception' do
|
12
|
+
expect do
|
13
|
+
client.schema
|
14
|
+
end.to raise_error Graphlient::Errors::Server do |e|
|
15
|
+
expect(e.to_s).to eq 'the server responded with status 500'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|