Skip to content

Commit

Permalink
Allow swapping the HTTP stack.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Oct 26, 2017
1 parent 7052ae6 commit 69a0fd2
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 55 deletions.
26 changes: 20 additions & 6 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-10-26 10:54:26 -0400 using RuboCop version 0.47.1.
# on 2017-10-26 13:04:15 -0400 using RuboCop version 0.47.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument:
Exclude:
- 'lib/graphlient/adapters/http/adapter.rb'
- 'lib/graphlient/adapters/http/http_adapter.rb'

# Offense count: 1
Lint/UselessAssignment:
Exclude:
- 'spec/graphlient/client_query_spec.rb'

# Offense count: 11
# Offense count: 1
Metrics/AbcSize:
Max: 19

# Offense count: 12
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 185

# Offense count: 20
# Offense count: 25
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 177

# Offense count: 2
# Offense count: 3
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 12
Expand All @@ -34,12 +46,14 @@ Style/ClassAndModuleChildren:
Exclude:
- 'spec/graphlient/static_client_query_spec.rb'

# Offense count: 6
# Offense count: 8
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/graphlient/adapters/faraday_adapter.rb'
- 'lib/graphlient/adapters/http/adapter.rb'
- 'lib/graphlient/adapters/http/faraday_adapter.rb'
- 'lib/graphlient/adapters/http/http_adapter.rb'
- 'lib/graphlient/client.rb'
- 'lib/graphlient/errors/error.rb'
- 'lib/graphlient/errors/graphql.rb'
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### 0.0.9 (Next)

* [#28](https://github.com/ashkan18/graphlient/pull/28): Raise errors in `execute`, not only `query` - [@dblock](https://github.com/dblock).
* [#29](https://github.com/ashkan18/graphlient/pull/29): Added `Graphlient::Adapters::HTTP::HTTPAdapter` that replaces Faraday with `Net::HTTP` - [@dblock](https://github.com/dblock).
* Your contribution here.

### 0.0.8 (10/26/2017)
Expand Down
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,17 @@ query.to_s
# "\nquery{\n invoice(id: 10){\n line_items\n }\n }\n"
```

### Swapping the HTTP Stack

You can swap the default Faraday adapter for `Net::HTTP`.

```ruby
client = Graphlient::Client.new('https://test-graphql.biz/graphql', http: Graphlient::Adapters::HTTP::HTTPAdapter)
```

### Testing with Graphlient and RSpec

Use Graphlient inside your RSpec tests in a Rails application or with `Rack::Test`, no more messy HTTP POSTs.
Use Graphlient inside your RSpec tests in a Rails application or with `Rack::Test` against your actual application.

```ruby
require 'spec_helper'
Expand Down Expand Up @@ -307,6 +315,25 @@ describe App do
end
```

Alternately you can `stub_request` with Webmock.

```ruby
describe App do
let(:client) { Graphlient::Client.new('http://example.com/graphql') }

before do
stub_request(:post, url).to_return(
status: 200,
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
)
end

it 'retrieves schema' do
expect(client.schema).to be_a GraphQL::Schema
end
end
```

## License

MIT License, see [LICENSE](LICENSE)
Expand Down
2 changes: 2 additions & 0 deletions lib/graphlient.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'graphql/client'
require 'graphlient/version'
require 'graphlient/extensions'
require 'graphlient/errors'
require 'graphlient/query'
require 'graphlient/adapters'
require 'graphlient/client'
1 change: 1 addition & 0 deletions lib/graphlient/adapters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative 'adapters/http'
43 changes: 0 additions & 43 deletions lib/graphlient/adapters/faraday_adapter.rb

This file was deleted.

3 changes: 3 additions & 0 deletions lib/graphlient/adapters/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require_relative 'http/adapter'
require_relative 'http/faraday_adapter'
require_relative 'http/http_adapter'
23 changes: 23 additions & 0 deletions lib/graphlient/adapters/http/adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Graphlient
module Adapters
module HTTP
class Adapter
attr_accessor :url, :options

def initialize(url, options = {}, &_block)
@url = url
@options = options.dup if options
yield self if block_given?
end

def headers
options[:headers] if options
end

def execute(document:, operation_name:, variables:, context:)
raise NotImplementedError
end
end
end
end
end
37 changes: 37 additions & 0 deletions lib/graphlient/adapters/http/faraday_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'faraday'
require 'faraday_middleware'

module Graphlient
module Adapters
module HTTP
class FaradayAdapter < Adapter
def execute(document:, operation_name:, variables:, context:)
response = connection.post do |req|
req.headers.merge!(context[:headers] || {})
req.body = {
query: document.to_query_string,
operationName: operation_name,
variables: variables.to_json
}.to_json
end
response.body
rescue Faraday::ClientError => e
raise Graphlient::Errors::Server.new(e.message, e)
end

def connection
@connection ||= Faraday.new(url: url, headers: headers) do |c|
c.use Faraday::Response::RaiseError
c.request :json
c.response :json
if block_given?
yield c
else
c.use Faraday::Adapter::NetHttp
end
end
end
end
end
end
end
39 changes: 39 additions & 0 deletions lib/graphlient/adapters/http/http_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'graphql/client/http'

module Graphlient
module Adapters
module HTTP
class HTTPAdapter < Adapter
attr_reader :uri

def execute(document:, operation_name: nil, variables: {}, context: {})
request = Net::HTTP::Post.new(url)

request['Accept'] = 'application/json'
request['Content-Type'] = 'application/json'
headers&.each { |name, value| request[name] = value }

body = {}
body['query'] = document.to_query_string
body['variables'] = variables if variables.any?
body['operationName'] = operation_name if operation_name
request.body = JSON.generate(body)

response = connection.request(request)
raise Graphlient::Errors::Server.new("the server responded with status #{response.code}", response) unless response.is_a?(Net::HTTPOK)
JSON.parse(response.body)
end

def uri
@uri ||= URI(url)
end

def connection
Net::HTTP.new(uri.host, uri.port).tap do |client|
client.use_ssl = uri.scheme == 'https'
end
end
end
end
end
end
9 changes: 5 additions & 4 deletions lib/graphlient/client.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
require 'graphql/client'
require 'graphlient/adapters/faraday_adapter'

module Graphlient
class Client
attr_accessor :uri, :options
Expand Down Expand Up @@ -40,8 +37,12 @@ def query(query_or_variables = nil, variables = nil, &block)
end
end

def http_adapter_class
options[:http] || Adapters::HTTP::FaradayAdapter
end

def http(&block)
@http ||= Adapters::FaradayAdapter.new(@url, headers: @options[:headers], &block)
@http ||= http_adapter_class.new(@url, headers: @options[:headers], &block)
end

def schema
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'spec_helper'

describe Graphlient::Adapters::FaradayAdapter do
describe Graphlient::Adapters::HTTP::FaradayAdapter do
let(:app) { Object.new }

context 'with a custom middleware' do
Expand Down Expand Up @@ -41,4 +41,20 @@
expect(client.http.headers).to eq headers
end
end

context 'default' do
let(:url) { 'http://example.com/graphql' }
let(:client) { Graphlient::Client.new(url) }

before do
stub_request(:post, url).to_return(
status: 200,
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
)
end

it 'retrieves schema' do
expect(client.schema).to be_a GraphQL::Schema
end
end
end
41 changes: 41 additions & 0 deletions spec/graphlient/adapters/http/http_adapter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'spec_helper'

describe Graphlient::Adapters::HTTP::HTTPAdapter do
let(:app) { Object.new }

context 'with custom url and headers' do
let(:url) { 'http://example.com/graphql' }
let(:headers) { { 'Foo' => 'bar' } }
let(:client) do
Graphlient::Client.new(url, headers: headers, http: Graphlient::Adapters::HTTP::HTTPAdapter)
end

it 'sets adapter' do
expect(client.http).to be_a Graphlient::Adapters::HTTP::HTTPAdapter
end

it 'sets url' do
expect(client.http.url).to eq url
end

it 'sets headers' do
expect(client.http.headers).to eq headers
end
end

context 'default' do
let(:url) { 'http://example.com/graphql' }
let(:client) { Graphlient::Client.new(url, http: Graphlient::Adapters::HTTP::HTTPAdapter) }

before do
stub_request(:post, url).to_return(
status: 200,
body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
)
end

it 'retrieves schema' do
expect(client.schema).to be_a GraphQL::Schema
end
end
end

0 comments on commit 69a0fd2

Please sign in to comment.