Created
February 10, 2012 22:56
-
-
Save jadeallenx/1793796 to your computer and use it in GitHub Desktop.
Erlang parameter validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% Post/Query string parameter validation. | |
% | |
% Mark Allen, [email protected] | |
% | |
% Specs [{{name, "param_name"}, {required, true}, {type, function}}, ... ] | |
% Input [{"name", "value}, ...] just you'd get from post or query string parameters | |
-module(t). | |
-export([test/0, test1/0, test2/0]). | |
find_spec(P, S) -> | |
case S of | |
{{name, P}, R, V} -> | |
{{name, P}, R, V}; | |
{{name, P}, V} -> | |
{{name, P}, {required, false}, V}; | |
{_, _, _} -> | |
skip; | |
{_, _} -> | |
skip | |
end. | |
validate_required(I, S) -> | |
InputParams = [ Name || {Name, _Value} <- I ], | |
R = [ case Bool of | |
true -> | |
ParamName; | |
false -> | |
false | |
end || {{_, ParamName}, {required, Bool}, {_, _}} <- S], | |
ReqParams = lists:filter(fun(A) -> A =/= false end, R), | |
V = [ lists:member(N, InputParams) || N <- ReqParams ], | |
[ case Bool of | |
true -> | |
{ok, Name}; | |
false -> | |
{missingreq, Name} | |
end || {Name, Bool} <- lists:zip(ReqParams, V) ]. | |
validate_specification(S, Acc) -> | |
case S of | |
{{name, Name}, {required, Bool}, {Type, F}} -> | |
Member = lists:member(Type, [int, string, atom, list, tuple]), | |
if | |
is_list(Name), is_boolean(Bool), Member == true, is_function(F) -> | |
{ok, Name}; | |
true -> | |
{badspec, Name} | |
end; | |
{{name, Name}, {Type, F}} -> | |
validate_specification({{name, Name}, {required, false}, {Type, F}}, Acc); | |
[H|T] -> | |
validate_specification(T, [validate_specification(H, Acc) | Acc]); | |
[] -> | |
lists:filter(fun(A) -> is_tuple(A) end, Acc) | |
end. | |
validate_params(Input, Spec) -> | |
[ case lists:filter(fun(A) -> A =/= skip end, [ find_spec(Name, S) || S <- Spec ]) of | |
[H|_T] -> | |
{{name, Name}, {required, _Bool}, {Type, F}} = H, | |
try | |
{ok, Coerce} = coerce_type(Type, Value), | |
case F(Coerce) of | |
true -> | |
{ok, Name, Coerce}; | |
false -> | |
{badparam, Name, Value} | |
end | |
catch | |
_:_ -> | |
{badparam, Name, Value} | |
end; | |
[] -> | |
{missingspec, Name} | |
end || {Name, Value} <- Input ]. | |
coerce_type(Type, Value) -> | |
case Type of | |
int when is_list(Value) -> | |
try | |
V = list_to_integer(Value), | |
{ok, V} | |
catch | |
_:_ -> | |
{badparam, Value} | |
end; | |
int when is_integer(Value) -> | |
{ok, Value}; | |
string when is_list(Value) -> | |
{ok, Value}; | |
binary when is_list(Value) -> | |
try | |
V = list_to_binary(Value), | |
{ok, V} | |
catch | |
_:_ -> | |
{badparam, Value} | |
end; | |
binary when is_binary(Value) -> | |
{ok, Value}; | |
tuple when is_list(Value) -> | |
try | |
V = list_to_tuple(Value), | |
{ok, V} | |
catch | |
_:_ -> | |
{badparam, Value} | |
end; | |
tuple when is_tuple(Value) -> | |
{ok, Value}; | |
list when is_list(Value) -> | |
{ok, Value} | |
end. | |
test() -> | |
Spec = [ | |
{{name, "foo"}, {required, true}, {int, fun(A) -> A > 50 end}}, | |
{{name, "bar"}, {required, false}, {string, fun(A) -> A =:= "quux" end}}, | |
{{name, "guz"}, {required, crap}, {string, fun(A) -> A =:= "quux" end}}, | |
{{name, gurz}, {required, crap}, {string, fun(A) -> A =:= "quux" end}}, | |
{{name, "baz"}, {int, fun(A) -> A =:= 0 end}}, | |
{{name, "bak"}, {crap, fun(A) -> A =:= 0 end}}, | |
{{name, "bez"}, {string, crap}}, | |
{{name, "vap"}, {int, fun(A) -> A < 0 end}} | |
% {{name, "zod"}}, | |
% {{name, "zux"}, {int}}, | |
% {{name, "faz"}, {fun(_A) -> true end}} | |
], | |
validate_specification(Spec, []). | |
test1() -> | |
Spec = [ | |
{{name, "foo"}, {required, true}, {int, fun(A) -> A > 50 end}}, | |
{{name, "bar"}, {required, false}, {string, fun(A) -> A =:= "quux" end}}, | |
{{name, "baz"}, {int, fun(A) -> A =:= 0 end}}, | |
{{name, "vap"}, {int, fun(A) -> A < 0 end}} | |
], | |
Input = [{"foo", "abc"}, {"bar", "quux"}, {"weasel", "bat"}], | |
validate_params(Input, Spec). | |
test2() -> | |
Spec = [ | |
{{name, "foo"}, {required, true}, {int, fun(A) -> A > 50 end}}, | |
{{name, "bar"}, {required, true}, {string, fun(A) -> A =:= "quux" end}}, | |
{{name, "baz"}, {int, fun(A) -> A =:= 0 end}}, | |
{{name, "vap"}, {int, fun(A) -> A < 0 end}} | |
], | |
Input = [{"foo", "abc"}, {"barf", "quux"}, {"baz", "bat"}], | |
validate_required(Input, Spec). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment