diff --git a/lib/seam/request.rb b/lib/seam/request.rb index ba87950..6d7a9e3 100644 --- a/lib/seam/request.rb +++ b/lib/seam/request.rb @@ -25,6 +25,12 @@ def self.create_faraday_client(endpoint, auth_headers, faraday_options = {}, far } options = deep_merge(default_options, faraday_options) + options.delete("headers") + options[:headers] = merge_headers( + faraday_options[:headers] || faraday_options["headers"] || {}, + auth_headers, + default_headers + ) default_faraday_retry_options = { max: 2, @@ -49,7 +55,6 @@ def self.create_faraday_client(endpoint, auth_headers, faraday_options = {}, far def self.default_headers { - "User-Agent" => "seam-ruby/#{Seam::VERSION}", "Content-Type" => "application/json", :"seam-sdk-name" => "seamapi/ruby", :"seam-sdk-version" => Seam::VERSION @@ -123,7 +128,23 @@ def self.deep_merge(hash1, hash2) result end - private_class_method :deep_merge + def self.merge_headers(*headers_list) + result = {} + header_keys = {} + + headers_list.each do |headers| + headers.each do |key, value| + normalized_key = key.to_s.downcase + result.delete(header_keys[normalized_key]) if header_keys.key?(normalized_key) + header_keys[normalized_key] = key + result[key] = value + end + end + + result + end + + private_class_method :deep_merge, :merge_headers end module UrlSearchParamsEncoder diff --git a/spec/seam_client/faraday_options_spec.rb b/spec/seam_client/faraday_options_spec.rb index ae7da9f..38a501e 100644 --- a/spec/seam_client/faraday_options_spec.rb +++ b/spec/seam_client/faraday_options_spec.rb @@ -27,6 +27,26 @@ expect(seam.client.headers["seam-sdk-name"]).to eq("seamapi/ruby") end + it "does not let faraday_options override auth or SDK headers" do + seam = described_class.new( + api_key: seed["seam_apikey1_token"], + endpoint: endpoint, + faraday_options: { + headers: { + "Authorization" => "Bearer caller_token", + "Content-Type" => "text/plain", + "Seam-Sdk-Name" => "caller-sdk", + :"seam-sdk-version" => "0.0.0" + } + } + ) + + expect(seam.client.headers["Authorization"]).to eq("Bearer #{seed["seam_apikey1_token"]}") + expect(seam.client.headers["Content-Type"]).to eq("application/json") + expect(seam.client.headers["seam-sdk-name"]).to eq("seamapi/ruby") + expect(seam.client.headers["seam-sdk-version"]).to eq(Seam::VERSION) + end + it "still authorizes requests against the server" do seam = described_class.new( api_key: seed["seam_apikey1_token"], diff --git a/spec/seam_client/headers_spec.rb b/spec/seam_client/headers_spec.rb index 3781fc0..13589ec 100644 --- a/spec/seam_client/headers_spec.rb +++ b/spec/seam_client/headers_spec.rb @@ -12,8 +12,7 @@ "Authorization" => "Bearer seam_some_api_key", "Content-Type" => "application/json", "seam-sdk-name" => "seamapi/ruby", - "seam-sdk-version" => Seam::VERSION, - "User-Agent" => "seam-ruby/#{Seam::VERSION}" + "seam-sdk-version" => Seam::VERSION } ) .to_return( @@ -29,6 +28,38 @@ expect(stub).to have_been_requested end + it "sends the SDK and auth headers over caller-provided duplicates" do + stub = stub_request(:get, "#{Seam::DEFAULT_ENDPOINT}/devices/get?device_id=#{device_id}&_strict=true") + .with( + headers: { + "Authorization" => "Bearer seam_some_api_key", + "Content-Type" => "application/json", + "seam-sdk-name" => "seamapi/ruby", + "seam-sdk-version" => Seam::VERSION + } + ) + .to_return( + status: 200, + body: {device: {device_id: device_id}}.to_json, + headers: {"Content-Type" => "application/json"} + ) + + seam = Seam.new( + api_key: "seam_some_api_key", + faraday_options: { + headers: { + "Authorization" => "Bearer caller_token", + "Content-Type" => "text/plain", + "Seam-Sdk-Name" => "caller-sdk", + :"seam-sdk-version" => "0.0.0" + } + } + ) + seam.devices.get(device_id: device_id) + + expect(stub).to have_been_requested + end + it "sends the workspace header with a personal access token" do stub = stub_request(:get, "#{Seam::DEFAULT_ENDPOINT}/devices/get?device_id=#{device_id}&_strict=true") .with(