From c452d94225e45f97ed692b31320cfd6f9c8f8729 Mon Sep 17 00:00:00 2001 From: Devin Date: Mon, 20 Jul 2026 22:05:31 +0000 Subject: [PATCH 1/2] Preserve explicit nil in request bodies as JSON null base_client no longer strips nil from mutating request bodies, so an explicit nil survives as JSON null. This is the hand-maintained runtime half of the nullable-clearing feature; the generated methods that pass nullable fields through arrive via regeneration from oagen-emitters#189. --- lib/workos/base_client.rb | 8 ++++---- test/workos/test_base_client.rb | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/workos/base_client.rb b/lib/workos/base_client.rb index f688a3c2..7fcc6522 100644 --- a/lib/workos/base_client.rb +++ b/lib/workos/base_client.rb @@ -66,7 +66,7 @@ def get_request(path:, auth: false, params: {}, request_options: nil) def post_request(path:, auth: false, body: {}, params: {}, request_options: nil) req = build_request(Net::HTTP::Post, append_query(path, params), auth: auth, request_options: request_options) - req.body = body.nil? ? "" : body.compact.to_json + req.body = body.nil? ? "" : body.to_json req["Content-Type"] = "application/json" inject_idempotency_key(req, request_options) req @@ -75,7 +75,7 @@ def post_request(path:, auth: false, body: {}, params: {}, request_options: nil) def put_request(path:, auth: false, body: {}, params: {}, request_options: nil) req = build_request(Net::HTTP::Put, append_query(path, params), auth: auth, request_options: request_options) - req.body = body.nil? ? "" : body.compact.to_json + req.body = body.nil? ? "" : body.to_json req["Content-Type"] = "application/json" inject_idempotency_key(req, request_options) req @@ -84,7 +84,7 @@ def put_request(path:, auth: false, body: {}, params: {}, request_options: nil) def patch_request(path:, auth: false, body: {}, params: {}, request_options: nil) req = build_request(Net::HTTP::Patch, append_query(path, params), auth: auth, request_options: request_options) - req.body = body.nil? ? "" : body.compact.to_json + req.body = body.nil? ? "" : body.to_json req["Content-Type"] = "application/json" inject_idempotency_key(req, request_options) req @@ -94,7 +94,7 @@ def delete_request(path:, auth: false, body: nil, params: {}, request_options: n req = build_request(Net::HTTP::Delete, append_query(path, params), auth: auth, request_options: request_options) if body - req.body = body.compact.to_json + req.body = body.to_json req["Content-Type"] = "application/json" end req diff --git a/test/workos/test_base_client.rb b/test/workos/test_base_client.rb index 73837d34..4998b159 100644 --- a/test/workos/test_base_client.rb +++ b/test/workos/test_base_client.rb @@ -119,6 +119,21 @@ def test_post_request_reads_idempotency_key_from_request_options assert_equal "idem_123", request["Idempotency-Key"] end + # The body is serialized verbatim (no `.compact`), so an explicit `nil` is + # sent as JSON `null` — this is what lets generated methods clear a nullable + # field. Omission is handled upstream in the generated method, not here. + def test_put_request_serializes_explicit_nil_as_json_null + request = @client.put_request(path: "/widgets/w_1", auth: true, body: {"external_id" => nil}) + + assert_equal({"external_id" => nil}, JSON.parse(request.body)) + end + + def test_post_request_serializes_explicit_nil_as_json_null + request = @client.post_request(path: "/widgets", auth: true, body: {"external_id" => nil}) + + assert_equal({"external_id" => nil}, JSON.parse(request.body)) + end + def test_retry_path_generates_idempotency_key_for_mutating_requests stub_request(:post, "https://api.workos.com/widgets") .to_return({status: 500, body: '{"message":"retry"}'}, {status: 200, body: "{}"}) From e44ab2da8cde8d0b59325e26e1eaf892cc6d2bbb Mon Sep 17 00:00:00 2001 From: Devin Date: Mon, 20 Jul 2026 22:08:28 +0000 Subject: [PATCH 2/2] Add nil-serialization tests for PATCH and DELETE --- test/workos/test_base_client.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/workos/test_base_client.rb b/test/workos/test_base_client.rb index 4998b159..5f17e4fb 100644 --- a/test/workos/test_base_client.rb +++ b/test/workos/test_base_client.rb @@ -134,6 +134,18 @@ def test_post_request_serializes_explicit_nil_as_json_null assert_equal({"external_id" => nil}, JSON.parse(request.body)) end + def test_patch_request_serializes_explicit_nil_as_json_null + request = @client.patch_request(path: "/widgets/w_1", auth: true, body: {"external_id" => nil}) + + assert_equal({"external_id" => nil}, JSON.parse(request.body)) + end + + def test_delete_request_serializes_explicit_nil_as_json_null + request = @client.delete_request(path: "/widgets/w_1", auth: true, body: {"external_id" => nil}) + + assert_equal({"external_id" => nil}, JSON.parse(request.body)) + end + def test_retry_path_generates_idempotency_key_for_mutating_requests stub_request(:post, "https://api.workos.com/widgets") .to_return({status: 500, body: '{"message":"retry"}'}, {status: 200, body: "{}"})