ruby-on-railsrubyfaraday

Faraday Response is never JSON


I can never get a JSON response from Faraday, within Ruby 3.1.3 and Faraday 2.7.5:

    def connection
      @connection ||= Faraday.new(
        url: url,
        headers: headers
      ) do |faraday|
        faraday.response :json
        faraday.request :json
      end
    end

    def headers
      { content_type: 'application/json',
        accept: 'application/json' }
    end

    def send_request
      connection.send(method) do |req|
        req.body = body
      end
    end

When running though, I check response.body, and it is never JSON (even though I have faraday.response :json:

[1] pry(#<App>)> response.body
=> "{\"data\":{\"date\":\"some_data\"}}"

I have to:

[2] pry(#<>)> JSON.parse response.body
=> {"data"=>{"date"=>"some_data"}}

The test I am checking this with is:

 let(:response_body) { { data: { date: 'some_data' } }.to_json }
 
 ...

stub_request(:post, url)
  .with(
     body: body.to_json,
     headers: custom_headers
   ).to_return(status: status, body: response_body, headers: {})
end

it 'POSTS to a url' do
  subject
  expect(a_request(:post, url)).to have_been_made
 end
end

Is my test wrong, or is the client code wrong to have json always returned?


Solution

  • My guess is that the API you are requesting is not setting the right content-type response header.

    I haven't dug very deep in the Faraday code, but it seems that if the response is not in format 'application/json' the response.body is delivered as plain string.

    conn = Faraday.new do |f|
       f.request :json 
       f.response :json
    end
    
    res = conn.get("https://dummyjson.com/products/1")
    res.body["id"]
    # => 1
    
    res.body.class
    # => Hash
    
    res.headers["content-type"]
    # => "application/json; charset=utf-8"
    
    res = conn.get("https://example.com")
    res.headers["content-type"]
    # => "text/html; charset=UTF-8"
    
    res.body[0, 80]
    # => "<!doctype html>\n<html>\n<head>\n    <title>Example Domain</title>\n\n    <meta chars"
    
    res.body.class
    # => String