From f20de67813009cc32f9586df397e950faa9011c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez=20Pi=C3=B1eiro?= <53467003+DavidGonzalezPineiro@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:49:07 +0100 Subject: [PATCH 1/2] fix: validation error array query params --- lib/open_api_spex/cast_parameters.ex | 14 +++++++++- test/operation2_test.exs | 42 +++++++++++++++++++++++----- test/plug/cast_test.exs | 12 ++++++++ test/support/user_controller.ex | 10 +++++-- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/lib/open_api_spex/cast_parameters.ex b/lib/open_api_spex/cast_parameters.ex index 1155cb79..6678f91d 100644 --- a/lib/open_api_spex/cast_parameters.ex +++ b/lib/open_api_spex/cast_parameters.ex @@ -39,7 +39,11 @@ defmodule OpenApiSpex.CastParameters do end defp get_params_by_location(conn, :query, _) do - Plug.Conn.fetch_query_params(conn).query_params + params = Plug.Conn.fetch_query_params(conn).query_params + Enum.reduce(params, %{}, fn param, acc -> + {updated_key, updated_value} = parse_query_param(param) + Map.update(acc, updated_key, updated_value, &[&1 | updated_value]) + end) end defp get_params_by_location(conn, :path, _) do @@ -61,6 +65,14 @@ defmodule OpenApiSpex.CastParameters do do: {property_name, value} end + defp parse_query_param({key, value}) when is_list(value) do + {"#{key}[]", value} + end + + defp parse_query_param(param) do + param + end + defp create_location_schema(parameters, components) do { %Schema{ diff --git a/test/operation2_test.exs b/test/operation2_test.exs index 9eeba145..e308b56c 100644 --- a/test/operation2_test.exs +++ b/test/operation2_test.exs @@ -50,6 +50,12 @@ defmodule OpenApiSpex.Operation2Test do @user_index %Operation{ operationId: "UserController.index", parameters: [ + Operation.parameter( + :"ids[]", + :query, + %Schema{type: :array, items: %Schema{type: :integer}}, + "Filter by user ids" + ), Operation.parameter(:name, :query, :string, "Filter by user name"), Operation.parameter(:age, :query, :integer, "Filter by user age"), %Reference{"$ref": "#/components/parameters/member"}, @@ -299,13 +305,21 @@ defmodule OpenApiSpex.Operation2Test do end test "casts valid query params and respects defaults" do - valid_query_params = %{"name" => "Rubi", "age" => "31", "member" => "true"} + valid_query_params = %{"ids[]" => 1, "name" => "Rubi", "age" => "31", "member" => "true"} assert {:ok, conn} = do_index_cast(valid_query_params) - assert conn.params == %{age: 31, member: true, name: "Rubi", include_archived: false} + + assert conn.params == %{ + "ids[]": [1], + age: 31, + member: true, + name: "Rubi", + include_archived: false + } end test "casts valid query params and overrides defaults" do valid_query_params = %{ + "ids[]" => 1, "name" => "Rubi", "age" => "31", "member" => "true", @@ -313,15 +327,29 @@ defmodule OpenApiSpex.Operation2Test do } assert {:ok, conn} = do_index_cast(valid_query_params) - assert conn.params == %{age: 31, member: true, name: "Rubi", include_archived: true} + + assert conn.params == %{ + "ids[]": [1], + age: 31, + member: true, + name: "Rubi", + include_archived: true + } end test "cast valid query params with replace_params: false" do - valid_query_params = %{"name" => "Rubi", "age" => "31", "member" => "true"} + valid_query_params = %{"ids[]" => 1, "name" => "Rubi", "age" => "31", "member" => "true"} assert {:ok, conn} = do_index_cast(valid_query_params, replace_params: false) - assert Plug.Conn.fetch_query_params(conn).params == valid_query_params + + assert Plug.Conn.fetch_query_params(conn).params == %{ + "ids" => ["1"], + "name" => "Rubi", + "age" => "31", + "member" => "true" + } assert conn.private.open_api_spex.params == %{ + "ids[]": [1], age: 31, member: true, name: "Rubi", @@ -330,9 +358,9 @@ defmodule OpenApiSpex.Operation2Test do end test "casts valid query params without applying defaults" do - valid_query_params = %{"name" => "Rubi", "age" => "31", "member" => "true"} + valid_query_params = %{"ids[]" => 1, "name" => "Rubi", "age" => "31", "member" => "true"} assert {:ok, conn} = do_index_cast(valid_query_params, apply_defaults: false) - assert conn.params == %{age: 31, member: true, name: "Rubi"} + assert conn.params == %{"ids[]": [1], age: 31, member: true, name: "Rubi"} end test "validate invalid data type for query param" do diff --git a/test/plug/cast_test.exs b/test/plug/cast_test.exs index 22b7e78f..2df5cf53 100644 --- a/test/plug/cast_test.exs +++ b/test/plug/cast_test.exs @@ -38,6 +38,18 @@ defmodule OpenApiSpex.Plug.CastTest do assert OpenApiSpex.params(conn) == %{validParam: true} end + test "ids[] param" do + conn = + :get + |> Plug.Test.conn("/api/users?ids[]=123") + |> OpenApiSpexTest.Router.call([]) + + assert conn.status == 200 + assert conn.private.open_api_spex.params == conn.params + + assert OpenApiSpex.params(conn) == %{"ids[]": [123]} + end + test "valid param with replace_params false" do conn = :get diff --git a/test/support/user_controller.ex b/test/support/user_controller.ex index b4522f66..4c59d222 100644 --- a/test/support/user_controller.ex +++ b/test/support/user_controller.ex @@ -15,7 +15,7 @@ defmodule OpenApiSpexTest.UserController do Show a user by ID """ @doc parameters: [ - id: [ + ids: [ in: :path, type: %Schema{type: :integer, minimum: 1}, description: "User ID", @@ -41,7 +41,13 @@ defmodule OpenApiSpexTest.UserController do List all users """ @doc parameters: [ - validParam: [in: :query, type: :boolean, description: "Valid Param", example: true] + validParam: [in: :query, type: :boolean, description: "Valid Param", example: true], + "ids[]": [ + in: :query, + type: %Schema{type: :array, items: %Schema{type: :integer}}, + description: "User IDs", + example: 123 + ] ], responses: [ ok: {"User List Response", "application/json", Schemas.UsersResponse} From b9256fc3afd6b32cd1167f02d11ae85cddf7de0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez=20Pi=C3=B1eiro?= <53467003+DavidGonzalezPineiro@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:27:06 +0100 Subject: [PATCH 2/2] style: format file according to coding standards --- lib/open_api_spex/cast_parameters.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/open_api_spex/cast_parameters.ex b/lib/open_api_spex/cast_parameters.ex index 6678f91d..bd44fe8b 100644 --- a/lib/open_api_spex/cast_parameters.ex +++ b/lib/open_api_spex/cast_parameters.ex @@ -40,6 +40,7 @@ defmodule OpenApiSpex.CastParameters do defp get_params_by_location(conn, :query, _) do params = Plug.Conn.fetch_query_params(conn).query_params + Enum.reduce(params, %{}, fn param, acc -> {updated_key, updated_value} = parse_query_param(param) Map.update(acc, updated_key, updated_value, &[&1 | updated_value])