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

Response body can't be a hash #449

Open
Morred opened this issue Jan 30, 2015 · 16 comments
Open

Response body can't be a hash #449

Morred opened this issue Jan 30, 2015 · 16 comments

Comments

@Morred
Copy link

Morred commented Jan 30, 2015

When I stub a request and specify a hash for the response body, I get the following error:

WebMock::Response::InvalidBody:
    must be one of: [Proc, IO, Pathname, String, Array]. 'Hash' given

Is there a particular reason why it can't be a hash?

@bblimke
Copy link
Owner

bblimke commented Jan 30, 2015

Please have a look at #427

If response body is declared as a hash, it's not clear what should the hash be encoded to. JSON, XML, or perhaps url params? Therefore WebMock expects you to stringify hash to expected encoding. I.e {a: b}.to_json

@Morred
Copy link
Author

Morred commented Feb 12, 2015

(Sorry for the late response, and thanks for your reply.)

I see, that makes sense. Maybe this should be mentioned in the Readme?

@joshuaswilcox
Copy link

I am not sure that makes sense. If a server is actually returning JSON as the body content, the code parsing can assume its a Hash content type, therefore calling JSON.parse(response) will fail if its already a Hash. So its seems to me that Webmock should be able to send that as the response body, especially when a content-type of 'application/json' is explicitly passed.

@bblimke
Copy link
Owner

bblimke commented Mar 23, 2015

"If a server is actually returning JSON as the body content" - which server do you mean? We are returning a stubbed response. This response will be passed through specific http client library internals. You can't expect these libs to handle Hash.

WebMock would have to convert Hash declared in to_return to json string automatically first, but how would it know whether to convert this Hash to json or to xml?

@joshuaswilcox
Copy link

Would it not be best to use the headers content-type to determine whether to return JSON or XML? I am stubbing as so

stub_request(:post,'http://......').
     to_return(
      :status => 200,
      :body => '{"transaction_status":"declined"}',
      :headers => {"Content-Type"=> "application/json"})

but would prefer not to have to call JSON.parse(response_body) since that is not a step that is required in my code as JSON is implicitly declared. Maybe I am missing something though? FWIW, I am using Faraday to make the actual request.

@bblimke
Copy link
Owner

bblimke commented Mar 23, 2015

In case there is response content type declared it could work. Webmock would have to raise an error is case body is declared as a hash and headers are not declared.

@bblimke
Copy link
Owner

bblimke commented Mar 23, 2015

Most people will forget about headers.

@joshuaswilcox
Copy link

I don't think that is a problem to require a content-type when passing certain types of body content, since that is generally a good practice across http requests. Could i make a pull request for this functionality?

@bblimke
Copy link
Owner

bblimke commented Mar 24, 2015

I don't think it's a problem either, as long as user gets a clear error message explaining content type needs to be added if missing.
Pull request would be most appreciated :)

@joshuaswilcox
Copy link

Great, thanks!

@s2t2
Copy link

s2t2 commented Oct 31, 2016

I support and encourage implementation of this feature.

I'm surprised this isn't a more widespread issue. I've already encountered this issue on two separate occasions with two different web services. Most recently I needed to implement a work-around whereby I changed my response-parsing method to handle/convert the stubbed response strings when in reality outside of the test environment this extra handling would not be required.

LDonoughe pushed a commit to LDonoughe/webmock that referenced this issue Oct 27, 2017
Doesn't support hashes in general

Re: bblimke#449
@pboling
Copy link

pboling commented Feb 10, 2018

I am running into this now. How is one supposed to mock a JSON response where the response is a hash? Not a JSON encoded string, but a hash. At the Ruby (Rails) layer the response is a hash in my real code, so it must also be in my test.

@bblimke
Copy link
Owner

bblimke commented Feb 10, 2018

@pboling

HTTP response body is never a hash (there is no Hash content type). Your ruby HTTP client most likely does the response body parsing for you and converts is to a Hash. In order for your http client to know that the response body is JSON, you need to indicate that by the Content-Type header.

stub_request(:get, 'http://......').
     to_return(
      body: json_string,
      headers: {"Content-Type"=> "application/json"})

@dduqueti
Copy link

dduqueti commented Apr 13, 2018

Thank you all for your answers, specially @joshuaswilcox and @bblimke. I was having issues with a spec for hours which mixed WebMock response with another gem expecting a hash. It wasn't until I ended up here that I was able to work through it. Had to use both JSON.generate and Content-Type suggestions.

I'm leaving my solution here:

stub_request(:get, /exampleurl.com/)
  .to_return(
     status: 200,
     body: JSON.generate(response_json),
     headers: {"Content-Type"=> "application/json"}
   )

LDonoughe pushed a commit to LDonoughe/webmock that referenced this issue Feb 6, 2020
Doesn't support hashes in general

Re: bblimke#449
benkoshy added a commit to benkoshy/webmock that referenced this issue Nov 5, 2020
Why this PR?

Right now, users might be confused as to why a hash cannot be accepted
as a response body? See Issue bblimke#449 on Github as well as bblimke#427.

This seems to have caused considerable consternation
to API users - with some spending many frustrated hours searching for a
solution. Perhaps it can be solved with a more helpful exception
message? This PR hopes to remedy this apparent shortcoming. Perhaps
I shall remedy it with an update to the documentation as well.

I submit it with the utmost respect to the maintainers and community.

Thank you for your efforts, and for reviewing.

Ben
@brian-lutz-informed
Copy link

brian-lutz-informed commented Nov 7, 2021

Thank you so much @bblimke @joshuaswilcox @dduqueti.

Assuming response is a hash and I'm writing a Rails app I can simplify @dduqueti's answer a little more using .to_json:

stub_request(:get, /exampleurl.com/)
  .to_return(
     status: 200,
     body: response.to_json,
     headers: {"Content-Type"=> "application/json"}
   )

@jeffdill2
Copy link

I think part of what makes this particularly confusing is that if you pass an empty hash, it doesn't throw an error.

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

10 participants