-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Thanks for you work on the project @ozziexsh !
I have found a issue when I am working with nested parameters. Here is my example...
The Problem
- Given I have the following validation rules defined - especially with
type: :mapspecified for the "address" param
def rules(conn) do
dbg() # <---- Callout: conn.params is %{} here
%{
"address" => [
required: false,
# Callout: The next line seems to cause the problem
type: :map,
nullable: true,
map: %{
"house_number" => [required: false, nullable: true, cast: :integer, between: {1, 50}]
}
]
}
end
- When I make a simple GET request in which I don't supply any "address" param
- Then I get the following validation errors...
[
%Validate.Validator.Error{
path: ["address"],
message: "expected map received nil",
rule: :type
}
]
Workaround
If I comment up the type: :map specified for the "address" param and repeat the experiment I get no validation errors (as expected). ie.
def rules(conn) do
dbg() # <---- Callout: conn.params is %{} here
%{
"address" => [
required: false,
# NB: Important: to *not* set type here or else map will blow up when no "page" params supplied at all
# type: :map,
nullable: true,
map: %{
"house_number" => [required: false, nullable: true, cast: :integer, between: {1, 50}]
}
]
}
end
Here is the example in a unit test...
test "it should allow a nested map param to *not* be supplied when type: :map and nullable: true and specified" do
rules =%{
"address" => [
required: false,
# Callout: The next line seems to cause the problem
type: :map,
nullable: true,
map: %{
"house_number" => [required: false, nullable: true, cast: :integer, between: {1, 50}]
}
]
}
# No address key supplied
input = %{}
assert {:ok, _} = Validate.validate(input, rules)
end
This test fails. If you comment out the type: map line it passes.
My Expectation
This issue occurred when I was used the plug / form request approach. In that scenario, when I stop submitting an "address" param with the HTTP request, the request param obviously does not get sent at all to the server (ie. I won't get a %{"address" => nil}, rather I will get %{} and that is problematic. I am not sure if the "nullable" option is behaving as you would expect in the above scenario - maybe it is. If it is behaving as expected then maybe a allow_missing: true option could be added? This would allow a param to be absent as well as present but nil - though that I what I would expect the required: false to allow me to do.
P.S. I can workaround the issue by not supplying type: :map of course - but that seems like a hack - really what I should be able to specify here is a map that can be missing.