diff --git a/lib/httpoison/base.ex b/lib/httpoison/base.ex index eb61119..780d3f1 100644 --- a/lib/httpoison/base.ex +++ b/lib/httpoison/base.ex @@ -995,6 +995,7 @@ defmodule HTTPoison.Base do {:form, Enum.flat_map(body, fn {k, [{_k, _v} | _rest] = v} -> flatten_nested_body(v, k) + {k, v} when is_map(v) -> flatten_nested_body(v, k) {k, v} -> [{k, v}] end)} end @@ -1006,6 +1007,9 @@ defmodule HTTPoison.Base do defp flatten_nested_body(body, parent_key) do flattened_body = Enum.reduce(body, [], fn + {key, nested_key_values}, acc when is_map(nested_key_values) -> + flatten_nested_body(nested_key_values, "#{parent_key}[#{key}]") ++ acc + {key, [{_key, _value} | _rest] = nested_key_values}, acc -> flatten_nested_body(nested_key_values, "#{parent_key}[#{key}]") ++ acc diff --git a/test/httpoison_test.exs b/test/httpoison_test.exs index a898ed4..85e2c68 100644 --- a/test/httpoison_test.exs +++ b/test/httpoison_test.exs @@ -82,7 +82,7 @@ defmodule HTTPoisonTest do ) end - test "post nested form data" do + test "post nested form data when given as keyword list" do assert_response( HTTPoison.post( "localhost:4002/post", @@ -105,6 +105,35 @@ defmodule HTTPoisonTest do ) end + test "post nested form data when given as map (no order guaranteed)" do + assert_response( + HTTPoison.post( + "localhost:4002/post", + {:form, %{not_nested: [1, 2], nested: %{foo: "bar", again: %{hello: "world"}}}}, + %{"Content-type" => "application/x-www-form-urlencoded"} + ), + fn %HTTPoison.Response{request: request} = response -> + assert {:form, body} = request.body + + assert [{:not_nested, [1, 2]}, {"nested[foo]", "bar"}, {"nested[again][hello]", "world"}] + |> MapSet.new() + |> MapSet.equal?(MapSet.new(body)) + + Regex.match?(~r/"not_nested".*\x01\x02/, response.body) + Regex.match?(~r/"nested\[foo\]".*"bar"/, response.body) + Regex.match?(~r/"nested\[again\]\[hello\]".*"world"/, response.body) + + assert {:ok, + "curl -X POST -H 'Content-type: application/x-www-form-urlencoded'" <> form_params} = + Request.to_curl(response.request) + + assert form_params =~ "-F 'not_nested=\x01\x02'" + assert form_params =~ "-F 'nested[foo]=bar'" + assert form_params =~ "-F 'nested[again][hello]=world'" + end + ) + end + test "put" do assert_response(HTTPoison.put("localhost:4002/put", "test"), fn response -> assert Request.to_curl(response.request) ==