From 6632f467813b6f97c9efc210a4af0446cda467e1 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Sat, 12 Sep 2026 13:10:52 -0400 Subject: [PATCH 1/2] Fix json >= 3.0 compatibility (#113) Replace Faraday's built-in :json response middleware, which calls JSON.parse(body, options) positionally, with Strava::Web::JsonResponse, a subclass that calls JSON.parse(body) with a single argument. This works with both json < 3.0 and json >= 3.0, which made options keyword-only. Also uncomments the json-3 appraisal in CI now that it passes, and removes the json ~> 2.3 pin from the Gemfile since it's no longer needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/test.yml | 11 +++++---- CHANGELOG.md | 1 + Gemfile | 6 ----- lib/strava-ruby-client.rb | 1 + lib/strava/web/connection.rb | 2 +- lib/strava/web/json_response.rb | 32 +++++++++++++++++++++++++++ spec/strava/web/json_response_spec.rb | 29 ++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 lib/strava/web/json_response.rb create mode 100644 spec/strava/web/json_response_spec.rb diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f4462e..926c2f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,14 +17,13 @@ jobs: gemfile: - Gemfile include: - # See https://github.com/dblock/strava-ruby-client/issues/113: json - # 2.x is the version this gem currently supports. json_3 is - # commented out until Faraday's :json middleware supports json >= - # 3.0, since it currently fails (Faraday::ParsingError). + # See https://github.com/dblock/strava-ruby-client/issues/113: this + # gem no longer relies on Faraday's built-in :json response + # middleware, so it works with both json < 3.0 and json >= 3.0. - ruby-version: "3.4" gemfile: gemfiles/json_2.gemfile - # - ruby-version: "3.4" - # gemfile: gemfiles/json_3.gemfile + - ruby-version: "3.4" + gemfile: gemfiles/json_3.gemfile env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 36a6601..1757a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### 3.1.1 (Next) * [#113](https://github.com/dblock/strava-ruby-client/issues/113): Adds Appraisals (`json-2`, `json-3`) - [@dblock](https://github.com/dblock). +* [#113](https://github.com/dblock/strava-ruby-client/issues/113): Fixed `ArgumentError` when parsing JSON responses with `json` gem >= 3.0 by replacing Faraday's built-in `:json` response middleware with a compatible one - [@dblock](https://github.com/dblock). * Your contribution here. ### 3.1.0 (2026/08/29) diff --git a/Gemfile b/Gemfile index 3bbd50f..e102e48 100755 --- a/Gemfile +++ b/Gemfile @@ -4,12 +4,6 @@ source 'http://rubygems.org' gemspec -# Faraday's :json response middleware is incompatible with json >= 3.0 (see -# https://github.com/dblock/strava-ruby-client/issues/113), so pin json here -# rather than relying on rubocop's own transitive constraint. The `json-3` -# appraisal (see Appraisals) is used to track when this can be removed. -gem 'json', '~> 2.3' - group :development, :test do gem 'appraisal' gem 'csv' diff --git a/lib/strava-ruby-client.rb b/lib/strava-ruby-client.rb index f013549..1a1e445 100644 --- a/lib/strava-ruby-client.rb +++ b/lib/strava-ruby-client.rb @@ -90,6 +90,7 @@ require_relative 'strava/models/zones' require_relative 'strava/web/raise_response_error' +require_relative 'strava/web/json_response' require_relative 'strava/web/connection' require_relative 'strava/web/api_response' require_relative 'strava/web/request' diff --git a/lib/strava/web/connection.rb b/lib/strava/web/connection.rb index 6a01dd4..7e3abcb 100644 --- a/lib/strava/web/connection.rb +++ b/lib/strava/web/connection.rb @@ -67,7 +67,7 @@ def connection connection.request :multipart connection.request :url_encoded connection.use Strava::Web::RaiseResponseError - connection.response :json + connection.use Strava::Web::JsonResponse connection.response :logger, logger if logger connection.adapter ::Faraday.default_adapter end diff --git a/lib/strava/web/json_response.rb b/lib/strava/web/json_response.rb new file mode 100644 index 0000000..0064e4a --- /dev/null +++ b/lib/strava/web/json_response.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Strava + module Web + # + # Faraday response middleware that parses JSON response bodies. + # + # This is a drop-in replacement for Faraday's built-in +:json+ response + # middleware (+Faraday::Response::Json+), which calls + # +JSON.parse(body, options)+ with a positional options hash. The + # +json+ gem 3.0 changed +JSON.parse+ to accept options as keyword + # arguments only, so that call raises + # +ArgumentError: wrong number of arguments (given 2, expected 1)+, + # surfaced by Faraday as +Faraday::ParsingError+. + # + # Overriding +#parse+ to call +JSON.parse+ with a single argument + # keeps this gem working with both +json+ < 3.0 and +json+ >= 3.0. + # + # @see https://github.com/dblock/strava-ruby-client/issues/113 + # @api private + # + class JsonResponse < ::Faraday::Response::Json + private + + def parse(body) + return if body.strip.empty? + + ::JSON.parse(body) + end + end + end +end diff --git a/spec/strava/web/json_response_spec.rb b/spec/strava/web/json_response_spec.rb new file mode 100644 index 0000000..a7009ad --- /dev/null +++ b/spec/strava/web/json_response_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Strava::Web::JsonResponse do + let(:middleware) { described_class.new } + + describe '#parse' do + it 'parses a JSON object body' do + expect(middleware.send(:parse, '{"foo":"bar"}')).to eq('foo' => 'bar') + end + + it 'parses a JSON array body' do + expect(middleware.send(:parse, '[1,2,3]')).to eq([1, 2, 3]) + end + + it 'returns nil for an empty body' do + expect(middleware.send(:parse, '')).to be_nil + end + + it 'returns nil for a blank body' do + expect(middleware.send(:parse, ' ')).to be_nil + end + + it 'does not raise ArgumentError with json >= 3.0 keyword-only JSON.parse' do + expect { middleware.send(:parse, '{}') }.not_to raise_error + end + end +end From db63d4233bd536a372a048b497ac9ca10910df22 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Thu, 17 Sep 2026 10:18:35 -0400 Subject: [PATCH 2/2] Require fixed Faraday JSON middleware Faraday 2.14.4 supports json 3 by forwarding parser options as\nkeyword arguments. Require that version and restore Faraday's built-in\n:json response middleware, removing the no-longer-needed local override.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/test.yml | 4 +--- Appraisals | 7 ++---- CHANGELOG.md | 2 +- lib/strava-ruby-client.rb | 1 - lib/strava/web/connection.rb | 2 +- lib/strava/web/json_response.rb | 32 --------------------------- spec/strava/web/json_response_spec.rb | 29 ------------------------ strava-ruby-client.gemspec | 2 +- 8 files changed, 6 insertions(+), 73 deletions(-) delete mode 100644 lib/strava/web/json_response.rb delete mode 100644 spec/strava/web/json_response_spec.rb diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 926c2f1..c77fa26 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,9 +17,7 @@ jobs: gemfile: - Gemfile include: - # See https://github.com/dblock/strava-ruby-client/issues/113: this - # gem no longer relies on Faraday's built-in :json response - # middleware, so it works with both json < 3.0 and json >= 3.0. + # See https://github.com/dblock/strava-ruby-client/issues/113. - ruby-version: "3.4" gemfile: gemfiles/json_2.gemfile - ruby-version: "3.4" diff --git a/Appraisals b/Appraisals index f04553b..9105571 100644 --- a/Appraisals +++ b/Appraisals @@ -1,10 +1,7 @@ # frozen_string_literal: true -# Tests the gem against the two major json releases that are relevant to -# https://github.com/dblock/strava-ruby-client/issues/113: json < 3.0, where -# JSON.parse accepts a positional options hash (the form Faraday's :json -# response middleware uses), and json >= 3.0, where JSON.parse only accepts -# keyword arguments and Faraday's call raises an ArgumentError. +# Tests the gem against the two major json releases relevant to +# https://github.com/dblock/strava-ruby-client/issues/113. appraise 'json-2' do gem 'json', '~> 2.3' end diff --git a/CHANGELOG.md b/CHANGELOG.md index 1757a3b..7941575 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ### 3.1.1 (Next) * [#113](https://github.com/dblock/strava-ruby-client/issues/113): Adds Appraisals (`json-2`, `json-3`) - [@dblock](https://github.com/dblock). -* [#113](https://github.com/dblock/strava-ruby-client/issues/113): Fixed `ArgumentError` when parsing JSON responses with `json` gem >= 3.0 by replacing Faraday's built-in `:json` response middleware with a compatible one - [@dblock](https://github.com/dblock). +* [#113](https://github.com/dblock/strava-ruby-client/issues/113): Supports `json` gem >= 3.0 by requiring Faraday >= 2.14.4 - [@dblock](https://github.com/dblock). * Your contribution here. ### 3.1.0 (2026/08/29) diff --git a/lib/strava-ruby-client.rb b/lib/strava-ruby-client.rb index 1a1e445..f013549 100644 --- a/lib/strava-ruby-client.rb +++ b/lib/strava-ruby-client.rb @@ -90,7 +90,6 @@ require_relative 'strava/models/zones' require_relative 'strava/web/raise_response_error' -require_relative 'strava/web/json_response' require_relative 'strava/web/connection' require_relative 'strava/web/api_response' require_relative 'strava/web/request' diff --git a/lib/strava/web/connection.rb b/lib/strava/web/connection.rb index 7e3abcb..6a01dd4 100644 --- a/lib/strava/web/connection.rb +++ b/lib/strava/web/connection.rb @@ -67,7 +67,7 @@ def connection connection.request :multipart connection.request :url_encoded connection.use Strava::Web::RaiseResponseError - connection.use Strava::Web::JsonResponse + connection.response :json connection.response :logger, logger if logger connection.adapter ::Faraday.default_adapter end diff --git a/lib/strava/web/json_response.rb b/lib/strava/web/json_response.rb deleted file mode 100644 index 0064e4a..0000000 --- a/lib/strava/web/json_response.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -module Strava - module Web - # - # Faraday response middleware that parses JSON response bodies. - # - # This is a drop-in replacement for Faraday's built-in +:json+ response - # middleware (+Faraday::Response::Json+), which calls - # +JSON.parse(body, options)+ with a positional options hash. The - # +json+ gem 3.0 changed +JSON.parse+ to accept options as keyword - # arguments only, so that call raises - # +ArgumentError: wrong number of arguments (given 2, expected 1)+, - # surfaced by Faraday as +Faraday::ParsingError+. - # - # Overriding +#parse+ to call +JSON.parse+ with a single argument - # keeps this gem working with both +json+ < 3.0 and +json+ >= 3.0. - # - # @see https://github.com/dblock/strava-ruby-client/issues/113 - # @api private - # - class JsonResponse < ::Faraday::Response::Json - private - - def parse(body) - return if body.strip.empty? - - ::JSON.parse(body) - end - end - end -end diff --git a/spec/strava/web/json_response_spec.rb b/spec/strava/web/json_response_spec.rb deleted file mode 100644 index a7009ad..0000000 --- a/spec/strava/web/json_response_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Strava::Web::JsonResponse do - let(:middleware) { described_class.new } - - describe '#parse' do - it 'parses a JSON object body' do - expect(middleware.send(:parse, '{"foo":"bar"}')).to eq('foo' => 'bar') - end - - it 'parses a JSON array body' do - expect(middleware.send(:parse, '[1,2,3]')).to eq([1, 2, 3]) - end - - it 'returns nil for an empty body' do - expect(middleware.send(:parse, '')).to be_nil - end - - it 'returns nil for a blank body' do - expect(middleware.send(:parse, ' ')).to be_nil - end - - it 'does not raise ArgumentError with json >= 3.0 keyword-only JSON.parse' do - expect { middleware.send(:parse, '{}') }.not_to raise_error - end - end -end diff --git a/strava-ruby-client.gemspec b/strava-ruby-client.gemspec index 86d4c5e..59b35ab 100644 --- a/strava-ruby-client.gemspec +++ b/strava-ruby-client.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s| s.licenses = ['MIT'] s.summary = 'Strava API Ruby client.' s.add_dependency 'activesupport' - s.add_dependency 'faraday', '>= 2.0' + s.add_dependency 'faraday', '>= 2.14.4' s.add_dependency 'faraday-multipart', '>= 1.0' s.add_dependency 'hashie' s.metadata['rubygems_mfa_required'] = 'true'