From e0116452940308bf0b2cb1b9e3342fc92752fef2 Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Tue, 8 Sep 2026 14:52:34 -0400 Subject: [PATCH] Return {} for a response with no body instead of raising TypeError Both Result classes parse the response body with a rescue for JSON::ParserError only. A response with a nil body -- 204 No Content from a subscriber destroy, or any provider that answers a success code with an empty payload -- reaches JSON.parse(nil), which raises TypeError, so Result.new blows up on a request that actually succeeded. parse_body / parsed now return {} for a nil or empty body before calling JSON.parse. successful? still falls through to the status code, so a 204 is reported as a success. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01GtYgwYNfJ3wHrw9xrooVoB --- lib/courrier/email/result.rb | 2 +- lib/courrier/subscriber/result.rb | 2 +- test/courrier/email/result_test.rb | 16 ++++++++++++++++ test/courrier/subscriber/result_test.rb | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/courrier/email/result.rb b/lib/courrier/email/result.rb index a268fb9..3f10a51 100644 --- a/lib/courrier/email/result.rb +++ b/lib/courrier/email/result.rb @@ -19,7 +19,7 @@ def success? = @success private def parse_body(body) - return {} if @response.nil? + return {} if body.nil? || body.empty? begin JSON.parse(body) diff --git a/lib/courrier/subscriber/result.rb b/lib/courrier/subscriber/result.rb index a55f2b0..2e13782 100644 --- a/lib/courrier/subscriber/result.rb +++ b/lib/courrier/subscriber/result.rb @@ -17,7 +17,7 @@ def success? = @success private def parsed(body) - return {} if @response.nil? + return {} if body.nil? || body.empty? begin JSON.parse(body) diff --git a/test/courrier/email/result_test.rb b/test/courrier/email/result_test.rb index 6a7850f..a17062e 100644 --- a/test/courrier/email/result_test.rb +++ b/test/courrier/email/result_test.rb @@ -31,6 +31,22 @@ def test_initialize_with_error assert_equal({}, result.data) end + def test_initialize_with_no_content_response + response = Data.define(:code, :body).new(code: "204", body: nil) + result = Courrier::Email::Result.new(response: response) + + assert result.success? + assert_equal({}, result.data) + end + + def test_initialize_with_empty_body + response = Data.define(:code, :body).new(code: "202", body: "") + result = Courrier::Email::Result.new(response: response) + + assert result.success? + assert_equal({}, result.data) + end + def test_success_predicate_method result = Courrier::Email::Result.new( response: Data.define(:code, :body).new(code: "200", body: "{}") diff --git a/test/courrier/subscriber/result_test.rb b/test/courrier/subscriber/result_test.rb index 4df16d3..f025154 100644 --- a/test/courrier/subscriber/result_test.rb +++ b/test/courrier/subscriber/result_test.rb @@ -33,6 +33,22 @@ def test_initialize_with_error assert_equal({}, result.data) end + def test_initialize_with_no_content_response + response = Data.define(:code, :body).new(code: "204", body: nil) + result = Courrier::Subscriber::Result.new(response: response) + + assert result.success? + assert_equal({}, result.data) + end + + def test_initialize_with_empty_body + response = Data.define(:code, :body).new(code: "200", body: "") + result = Courrier::Subscriber::Result.new(response: response) + + assert result.success? + assert_equal({}, result.data) + end + def test_success_predicate_method result = Courrier::Subscriber::Result.new( response: Data.define(:code, :body).new(code: "200", body: "{}")