Error with query String params
I am using the http gem in a rails api project.
I have a problem while making a "get" call to another rails api using the :params option . this function convert those params to string because of this they are not parsed.
Is there any solution to send "query params" instead of "query string params" ?
the query params sent using this gem :
/comments?filter=%7B%22title%22%3D%3E%22%22%2C+%22language%22%3D%3E%22%22%2C+%22region%22%3D%3E%22%22%2C+%22active%22%3D%3E%22%22%2C+%22
the query params form that i am seeking :
/comments?filter[post]=1,2&filter[author]=12 (JSON api filter form )
Thank you.
Can you post a code example? I very strongly suspect this is something wrong in your usage, and not a bug in the gem.
I've found this gem doesn't handle nested params natively and have resorted to using ActiveSupport's #to_query method
This request:
HTTP.get('https://requestb.in/qzba87qz', params: {filter: {post: '1,2', author: 12}})
makes this query request:
filter=%7B%3Apost%3D%3E%221%2C2%22%2C+%3Aauthor%3D%3E12%7D
which decodes to:
filter={:post=>"1,2",+:author=>12}
Using #to_query in a Rails app to construct the query string works right, though:
HTTP.get("https://requestb.in/qzba87qz?#{{filter: {post: '1,2', author: 12}}.to_query}")
makes this query request:
filter%5Bauthor%5D=12&filter%5Bpost%5D=1%2C2
decodes to:
filter[author]=12&filter[post]=1,2
Dear @tarcieri , i am using this code in my project
HTTP.get(url, params: { filter: { post: '1,2', author: 12 } }).
and the solution of Mr. @mikegee worked well , thanks a lot .
We use Rack::Utils.parse_nested_query and Rack::Utils.build_nested_query to work around this.
As far as I could tell, there isn't such thing as "nested query parameters" in the URI RFC. The discussion in https://github.com/sporkmonger/addressable/issues/77 provides some more context on that.
In short, Rails and some other web frameworks invented the filter[author] convention, as a way to specify nested parameters. That's why only Rack knows how to handle it, while URI and Addressable::URI don't (as far as I could tell).
I vote for keeping this functionality out of HTTP.rb, because we cannot pull it from URI nor Addressable::URI since it doesn't exist, we cannot depend on Rack/ActiveSupport either, and it wouldn't make sense for HTTP.rb to implement its own. Ultimately it's up to the Addressable maintainers to decide whether they will support nested parameters like this (though it seems they won't). So I think we can close this issue.
Note that there is also an alternative way which IMO is perfectly acceptable:
HTTP.get('https://requestb.in/qzba87qz', params: {"filter[post]" => "1,2", "filter[author]" => "2"})
@janko-m generally I totally agree. :D But I think we should provide swap-able interface for things like this.
So, let's keep this open for now.
What about providing a way to pass query parameters in their raw form (like body)? This would satisfy the existing implementation :params and more complex usages
@Fire-Dragon-DoL there's already a workaround of that nature posted above: https://github.com/httprb/http/issues/428#issuecomment-362472654
@Fire-Dragon-DoL there's already a workaround of that nature posted above: #428 (comment)
I saw that, however it introduces an additional challenge because of the double transformation, especially in contexts where trying to "proxy" query parameters from another HTTP request:
Query (string) format -> Rails format -> HTTPrb format -> HTTP Request
With the possibility to make mistakes between "rails format" and the HTTPrb format. If it was possible to pass a raw string for the query parameters, this would be the flow instead:
Query (string) format -> HTTP Request
It's also more likely that a library supports transforming into a query string than into the HTTPrb "params" format (which effectively is not really a format, rather a solution to a problem, I understand that).
Right now my solution was instead to take the query parameters, convert them to a query string and append them to the URL itself. Something along the line this sudo-code:
uri = URI(some_base_url)
uri.query = Rack::Utils.build_nested_query({ foo: ["bar", "baz"] })
HTTP.get(uri.to_s) # params entirely omitted
I believe there would be no harm in adding query: keyword (like we have for json: and form:). Or, we can allow passing String to params in which case we will treat it as is.
Either way, we need to think how to merge params if multiple sources are provided.
Currently, HTTP.get("https://example.com?a=1&b=2", params: { b: 3, c: 4 }) will send:
GET https://example.com/?a=1&b=2&b=3&c=4
Which is a bit confusing IMO. And even more so if you run:
HTTP.get("https://example.com?a=1&b=2", params: { b: 3, c: 4 }, json: { d: 5 }, form: { e: 6 })
Probably, the best would be to raise an ArgumentError in such case.