Reputation: 23
I'm sending a POST request using HTTParty. One of the variables required is an array. This is the code I'm using to send:
response = HTTParty.post url, :body =>
{"key"=>'XYZ123',
"content"=>
[{"placename"=>"placeholder",
"placecontent"=>"sample content"}],
etc. }
The API needs to see:
"content": [
{
"placename": "placeholder",
"placecontent": "sample content"
}
],
However, when I check the request received logs on the API, I see that my code is producing:
"content": [
{
"placename": "placeholder"
},
{
"placecontent": "sample content"
}
],
How can I stop the array record from being split in two?
Thanks.
EDIT: The desired output of the code is the equivalent of:
...&content[0][placename]=placeholder&content[0][placecontent]=sample%20content...
Upvotes: 2
Views: 4130
Reputation: 37419
By default, HTTParty
uses HashConversions
to convert a Hash
body to parameters:
Examples:
{ :name => "Bob", :address => { :street => '111 Ruby Ave.', :city => 'Ruby Central', :phones => ['111-111-1111', '222-222-2222'] } }.to_params #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111
Ruby Ave."
You can override this with your own convertor by using HTTParty.query_string_normalizer
:
Override the way query strings are normalized. Helpful for overriding the default rails normalization of Array queries.
For a query:
get '/', :query => {:selected_ids => [1,2,3]}
The default query string normalizer returns:
/?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
Let’s change it to this:
/?selected_ids=1&selected_ids=2&selected_ids=3
Pass a Proc to the query normalizer which accepts the yielded query.
@example Modifying Array query strings
class ServiceWrapper include HTTParty query_string_normalizer proc { |query| query.map do |key, value| value.map {|v| "#{key}=#{v}"} end.join('&') } end
@param [Proc] normalizer custom query string normalizer. @yield [Hash, String] query string @yieldreturn [Array] an array that will later be joined with ‘&’
or simply pass it in your options:
response = HTTParty.post url, :body =>
{"key"=>'XYZ123',
"content"=>
[{"placename"=>"placeholder",
"placecontent"=>"sample content"}]},
:query_string_normalizer => -> (h) { ... your own implementation here ...}
To get a serialization of a[1]=val1&a[2]=val2
instead of a[]=val1&a[]=val2
you can create your own HashConversions
based on the current one
class MyHashConversions
def to_params(hash)
params = hash.map { |k,v| normalize_param(k,v) }.join
params.chop! # trailing &
params
end
def normalize_param(key, value)
param = ''
stack = []
if value.is_a?(Array)
#### THE CHANGE IS HERE
param << value.each_with_index.map { |element, i| normalize_param("#{key}[#{i}]", element) }.join
####
elsif value.is_a?(Hash)
stack << [key,value]
else
param << "#{key}=#{URI.encode(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&"
end
stack.each do |parent, hash|
hash.each do |k, v|
if v.is_a?(Hash)
stack << ["#{parent}[#{k}]", v]
else
param << normalize_param("#{parent}[#{k}]", v)
end
end
end
param
end
end
The code above is not tested, but if it works, and is generic enough, you might consider forking the project and github, making the fix there, so it will work out of the box :)
Upvotes: 6