From 2dd7aee6cabd69091f900ccdf9212a193f1e1be8 Mon Sep 17 00:00:00 2001 From: Matias Salles Date: Wed, 17 Sep 2025 00:05:15 -0300 Subject: [PATCH 1/2] include headers in response --- lib/nylas/handler/http_client.rb | 19 +++++---- spec/nylas/handler/http_client_spec.rb | 53 +++++++++++++++++++++----- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/lib/nylas/handler/http_client.rb b/lib/nylas/handler/http_client.rb index d373140c..6e0e7a6b 100644 --- a/lib/nylas/handler/http_client.rb +++ b/lib/nylas/handler/http_client.rb @@ -41,7 +41,7 @@ def execute(method:, path:, timeout:, headers: {}, query: {}, payload: nil, api_ content_type = response.headers["content-type"].downcase end - parsed_response = parse_json_evaluate_error(result.code.to_i, response.body, path, content_type) + parsed_response = parse_json_evaluate_error(result.code.to_i, response.body, path, content_type, response.headers) # Include headers in the response parsed_response[:headers] = response.headers unless parsed_response.nil? parsed_response @@ -311,37 +311,36 @@ def handle_response(http, get_request, path, &block) end # Parses the response from the Nylas API and evaluates for errors. - def parse_json_evaluate_error(http_code, response, path, content_type = nil) + def parse_json_evaluate_error(http_code, response, path, content_type = nil, headers = nil) begin response = parse_response(response) if content_type == "application/json" rescue Nylas::JsonParseError - handle_failed_response(http_code, response, path) + handle_failed_response(http_code, response, path, headers) raise end - handle_failed_response(http_code, response, path) + handle_failed_response(http_code, response, path, headers) response end # Handles failed responses from the Nylas API. - def handle_failed_response(http_code, response, path) + def handle_failed_response(http_code, response, path, headers = nil) return if HTTP_SUCCESS_CODES.include?(http_code) + puts response.inspect + puts response.class.name case response when Hash - raise error_hash_to_exception(response, http_code, path) + raise error_hash_to_exception(response, http_code, path, headers) else raise NylasApiError.parse_error_response(response, http_code) end end # Converts error hashes to exceptions. - def error_hash_to_exception(response, status_code, path) + def error_hash_to_exception(response, status_code, path, headers = nil) return if !response || !response.key?(:error) - # Safely get headers without risking KeyError - headers = response.key?(:headers) ? response[:headers] : nil - if %W[#{api_uri}/v3/connect/token #{api_uri}/v3/connect/revoke].include?(path) NylasOAuthError.new(response[:error], response[:error_description], response[:error_uri], response[:error_code], status_code) diff --git a/spec/nylas/handler/http_client_spec.rb b/spec/nylas/handler/http_client_spec.rb index 34057eda..1848146f 100644 --- a/spec/nylas/handler/http_client_spec.rb +++ b/spec/nylas/handler/http_client_spec.rb @@ -318,6 +318,35 @@ class TestHttpClient expect(response).to eq(response_json.merge(headers: mock_headers)) end + it "returns an error with headers" do + response_json = { + foo: "bar", + error: { + type: "api_error", + message: "An unexpected error occurred", + provider_error: "This is the provider error" + } + } + request_params = { method: :get, path: "https://test.api.nylas.com/foo", timeout: 30 } + mock_headers = { + "content-type" => "application/json", + "x-request-id" => "123", + "some-header" => "value" + } + mock_response = instance_double("HTTParty::Response", + body: response_json.to_json, + headers: mock_headers, + code: 429) + + allow(HTTParty).to receive(:get).and_return(mock_response) + + expect do + http_client.send(:execute, **request_params) + end.to raise_error(Nylas::NylasApiError) { |error| + expect(error.headers).to eq(mock_headers) + } + end + it "raises a timeout error" do request_params = { method: :get, path: "https://test.api.nylas.com/foo", timeout: 30 } allow(HTTParty).to receive(:get).and_raise(Net::OpenTimeout) @@ -462,22 +491,22 @@ class TestHttpClient type: "api_error", message: "An unexpected error occurred", provider_error: "This is the provider error" - }, - headers: { - "x-request-id": "request-id-from-headers", - "x-ratelimit-limit": "100", - "x-ratelimit-remaining": "99" } } + headers = { + "x-request-id": "request-id-from-headers", + "x-ratelimit-limit": "100", + "x-ratelimit-remaining": "99" + } - err_obj = http_client.send(:error_hash_to_exception, response, 400, "https://test.api.nylas.com/foo") + err_obj = http_client.send(:error_hash_to_exception, response, 400, "https://test.api.nylas.com/foo", headers) expect(err_obj).to be_a(Nylas::NylasApiError) expect(err_obj.message).to eq("An unexpected error occurred") expect(err_obj.request_id).to eq("request-id") expect(err_obj.provider_error).to eq("This is the provider error") expect(err_obj.type).to eq("api_error") - expect(err_obj.headers).to eq(response[:headers]) + expect(err_obj.headers).to eq(headers) end end @@ -555,11 +584,17 @@ class TestHttpClient provider_error: "This is the provider error" } } + headers = { + "x-request-id": "request-id-from-headers", + "x-ratelimit-limit": "100", + } expect do http_client.send(:parse_json_evaluate_error, 400, response.to_json, - "https://test.api.nylas.com/foo", "application/json") - end.to raise_error(Nylas::NylasApiError) + "https://test.api.nylas.com/foo", "application/json", headers) + end.to raise_error(Nylas::NylasApiError) { |error| + expect(error.headers).to eq(headers) + } end it "raises a NylasApiError for a non-JSON response" do From cdc1226918e89bb4145e5acdd11d30c57893dcde Mon Sep 17 00:00:00 2001 From: Matias Salles Date: Wed, 17 Sep 2025 01:12:52 -0300 Subject: [PATCH 2/2] remove puts --- lib/nylas/handler/http_client.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/nylas/handler/http_client.rb b/lib/nylas/handler/http_client.rb index 6e0e7a6b..b5104898 100644 --- a/lib/nylas/handler/http_client.rb +++ b/lib/nylas/handler/http_client.rb @@ -327,8 +327,6 @@ def parse_json_evaluate_error(http_code, response, path, content_type = nil, hea def handle_failed_response(http_code, response, path, headers = nil) return if HTTP_SUCCESS_CODES.include?(http_code) - puts response.inspect - puts response.class.name case response when Hash raise error_hash_to_exception(response, http_code, path, headers)