0

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?

I. Khan
  • 169
  • 6
  • See the docs for [JSON Response Middleware](https://lostisland.github.io/faraday/middleware/json-response) – by default, the `content_type` has to match `/\bjson$/`. Your test should pass once you return the correct header, e.g. `headers: {content_type: 'application/json'}`. If an actual API is failing to send the header, you can adjust the middleware's pattern. – Stefan May 31 '23 at 09:12

1 Answers1

0

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
Fer
  • 3,247
  • 1
  • 22
  • 33
  • Duh - that was it! I put `headers: { 'Content-Type': 'application/json' }` for the `stub_request` and all worked fine! Thank you! – I. Khan May 31 '23 at 13:46