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