Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

* Added/Changed/Deprecated/Removed/Fixed/Security: YOUR CHANGE HERE
* Fixed: multipart adapter raises `Graphlient::Errors::FaradayServerError` on 5xx responses instead of passing HTML error pages on as the body
* Added: automatic conversion from symbols to keywords setting
* Added: relation.empty?, relation.blank?, relation.present? methods
* Added: fields now can be marked as "keywords"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@ module Adapters
class GraphlientMultipartAdapter < Graphlient::Adapters::HTTP::Adapter
def execute(document:, operation_name:, variables:, context:)
response = execute_request(document:, operation_name:, variables:, context:)
raise_server_error(response) if response.status >= 500

response.body
rescue Faraday::ClientError => e
rescue Faraday::ClientError, Faraday::ServerError => e
raise Graphlient::Errors::FaradayServerError, e
end

private

# 4xx bodies may still carry GraphQL errors, so only 5xx are treated as transport failures.
def raise_server_error(response)
raise Faraday::ServerError.new("the server responded with status #{response.status}", response.to_hash)
end

def execute_request(document:, operation_name:, variables:, context:)
connection.post do |req|
req.headers.merge!(context[:headers] || {})
Expand All @@ -32,7 +39,6 @@ def execute_request(document:, operation_name:, variables:, context:)

def connection
@connection ||= Faraday.new(url:, headers:) do |c|
c.adapter Faraday::Response::RaiseError
c.request :multipart
c.request :url_encoded
c.response :json
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

require 'spec_helper'
require 'active_graphql/client/adapters/graphlient_multipart_adapter'

class ActiveGraphql::Client
RSpec.describe Adapters::GraphlientMultipartAdapter do
subject(:adapter) { described_class.new(url) }

let(:url) { 'http://example.com/graphql' }
let(:document) { GraphQL.parse('mutation { createUser { id } }') }

describe '#execute' do
subject(:execute) { adapter.execute(document:, operation_name: nil, variables: {}, context: {}) }

context 'when server responds with JSON' do
before do
stub_request(:post, url).to_return(
status: 200,
body: { data: { createUser: { id: 1 } } }.to_json,
headers: { 'Content-Type' => 'application/json' }
)
end

it 'returns parsed body' do
expect(execute).to eq('data' => { 'createUser' => { 'id' => 1 } })
end
end

context 'when server responds with 503 HTML page' do
before do
stub_request(:post, url).to_return(
status: 503,
body: '<html><body><h1>503 Service Unavailable</h1></body></html>',
headers: { 'Content-Type' => 'text/html' }
)
end

it 'raises FaradayServerError with status code' do
expect { execute }.to raise_error(Graphlient::Errors::FaradayServerError) do |error|
expect(error.status_code).to eq 503
end
end
end

context 'when server responds with 4xx containing GraphQL errors' do
before do
stub_request(:post, url).to_return(
status: 422,
body: { errors: [{ message: 'invalid' }] }.to_json,
headers: { 'Content-Type' => 'application/json' }
)
end

it 'returns body so GraphQL errors can be handled' do
expect(execute).to eq('errors' => [{ 'message' => 'invalid' }])
end
end
end
end
end
Loading