Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faraday::Response::Json not loaded by default with Faraday 1 #1594

Closed
jrmhaig opened this issue Sep 19, 2024 · 6 comments
Closed

Faraday::Response::Json not loaded by default with Faraday 1 #1594

jrmhaig opened this issue Sep 19, 2024 · 6 comments

Comments

@jrmhaig
Copy link

jrmhaig commented Sep 19, 2024

Basic Info

  • Faraday Version: 1.10.3
  • Ruby Version: 3.3.5

Issue description

Faraday::Response::Json is not loaded by default. This class was created in #1400 specifically to allow the two versions to be used interchangeably, so that gems that use Faraday can support both. However, this class is loaded automatically with version 2 so its use is not exactly interchangeable.

Steps to reproduce

irb(main):001> require 'faraday'
=> true
irb(main):002> Faraday::Response::Json
(irb):2:in `<main>': uninitialized constant Faraday::Response::Json (NameError)

Faraday::Response::Json
                 ^^^^^^
	from <internal:kernel>:187:in `loop'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/irb-1.13.1/exe/irb:9:in `<top (required)>'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/bin/irb:25:in `load'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/bin/irb:25:in `<top (required)>'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:58:in `load'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:58:in `kernel_load'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:23:in `run'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli.rb:451:in `exec'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli.rb:34:in `dispatch'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/cli.rb:28:in `start'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/exe/bundle:28:in `block in <top (required)>'
	from /Users/joseph.haig/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bundler-2.5.3/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
	... 3 levels...
irb(main):003> require 'faraday/response/json'
=> true
irb(main):004> Faraday::Response::Json
=> Faraday::Response::Json

For reference, with Faraday 2:

irb(main):001> require 'faraday'
=> true
irb(main):002> Faraday::Response::Json
=> Faraday::Response::Json
@iMacTia
Copy link
Member

iMacTia commented Sep 19, 2024

Hi @jrmhaig this shouldn't be causing issues because you'd normally use the registered symbol to load the middleware rather than the fully qualified class name:

Faraday.new(...) do |f|
  f.response :json # rather than `f.use Faraday::Response::Json`
end

This should work because the Faraday::Response::Json class will get auto-loaded for you.
Right now I can't recall why we didn't explicitly require it, it might have to do with conflicts when faraday_middleware is included in the bundle.

If there's any reason why this is actually causing issues I might investigate further, please let me know if the above doesn't work for you or if you have a specific use-case

@jrmhaig
Copy link
Author

jrmhaig commented Sep 19, 2024

Thank you for the quick response. I haven't put together a minimal working example yet so I would hold off doing any further investigation if I were you.

I am seeing the issue in this PR - ministryofjustice/laa-court-data-ui#2044 - which updates the json_api_client gem to a version that supports Faraday 2. I initially thought that this had removed support for Faraday 1 but I now understand that both versions should be supported. It is possible that there is a conflict with faraday_middleware, as you mention, as we need it for another middleware.

@jrmhaig
Copy link
Author

jrmhaig commented Sep 19, 2024

OK, so it appears that it is the conflict with faraday_middleware that is causing the problem. This is the minimal working example I found:

require 'json_api_client'
require 'faraday_middleware'

module ScienceMuseum
  class Base < JsonApiClient::Resource
    self.site = 'https://collection.sciencemuseumgroup.org.uk/search'

    connection do |conn|
      conn.use(
        FaradayMiddleware::OAuth2,
        'asdf',
        token_type: :bearer
      )
    end
  end

  class Object < Base
  end

  class Person < Base
  end

  class Place < Base
  end
end

x = ScienceMuseum::Object.all
pp x

OAuth isn't actually required for this particular API but it is enough in this example to repeat the error at the conn.use line.

I believe that there is a better way using the oauth2 gem instead of middleware so that is a way forward in our real use case. Sorry to trouble you with this.

@iMacTia
Copy link
Member

iMacTia commented Sep 20, 2024

After reproducing this locally and taking a closer look, I concluded we likely forgot to update the "autoloader".
I tested adding Faraday::Request::Json and Faraday::Response::Json there and there no class conflicts with faraday_middleware.
I've opened #1595 to address this.

The only "conflict" now is on the registered :json middleware as indicated in #1400 description notes, meaning the faraday_middleware json middleware will be picked when f.response :json is used.

This would still cause issues in json_api_client because they call builder.response :json (see this line) which will inject the FaradayMiddleware::ParseJson in the stack if faraday_middleware is loaded, and then look for Faraday::Response::Json (see this line) in the #use method.

Possible workarounds here would be:

  1. json_api_client looks for either Faraday::Response::Json or FaradayMiddleware::ParseJson.
  2. Projects using both json_api_client AND faraday_middleware can force-load Faraday::Response::Json AFTER faraday_middleware to ensure this will be registered last and take priority.

Neither of the above look good though, because it would require either the gem authors or the user to know about this particular setup 😞
Instead, it would be great if faraday_middleware would skip registering the :json middleware if Faraday::Response::Json is already registered.

It would take some additional time and tinkering, but that should be possible in theory 🤔

@iMacTia
Copy link
Member

iMacTia commented Sep 23, 2024

We've now released a new version of faraday_middleware that won't register the json middleware if it finds the out-of-the-box one 🙌
This should improve the overall experience and solve the remaining issues highlighted on my previous comment.

@jrmhaig if you could give it a try in your project, it would be greatly appreciated ❤️

I'm gonna close this issue now but please let me know if you manage to try it out!

@iMacTia iMacTia closed this as completed Sep 23, 2024
@jrmhaig
Copy link
Author

jrmhaig commented Sep 24, 2024

Thanks. That's fantastic. I have upgraded json_api_client and faraday_middleware successfully (ministryofjustice/laa-court-data-ui#2436) and it all appears to be working correctly. I didn't realise that there was also an update to faraday so that one doesn't seem to be strictly necessary, although I will be upgrading that too shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants