|
@@ -5,7 +5,7 @@ Constraints are validation and conversion functions applied
|
|
to user input.
|
|
to user input.
|
|
|
|
|
|
They are used in various places in Cowboy, including the
|
|
They are used in various places in Cowboy, including the
|
|
-router and the request match functions.
|
|
|
|
|
|
+router and the `cowboy_req` match functions.
|
|
|
|
|
|
=== Syntax
|
|
=== Syntax
|
|
|
|
|
|
@@ -36,10 +36,18 @@ check that the integer is positive:
|
|
|
|
|
|
[source,erlang]
|
|
[source,erlang]
|
|
----
|
|
----
|
|
-PositiveFun = fun(V) when V > 0 -> true; (_) -> false end,
|
|
|
|
|
|
+PositiveFun = fun
|
|
|
|
+ (_, V) when V > 0 ->
|
|
|
|
+ {ok, V};
|
|
|
|
+ (_, _) ->
|
|
|
|
+ {error, not_positive}
|
|
|
|
+end,
|
|
{my_value, [int, PositiveFun]}.
|
|
{my_value, [int, PositiveFun]}.
|
|
----
|
|
----
|
|
|
|
|
|
|
|
+We ignore the first fun argument in this snippet. We shouldn't.
|
|
|
|
+We will simply learn what it is later in this chapter.
|
|
|
|
+
|
|
When there's only one constraint, it can be provided directly
|
|
When there's only one constraint, it can be provided directly
|
|
without wrapping it into a list:
|
|
without wrapping it into a list:
|
|
|
|
|
|
@@ -62,30 +70,54 @@ Built-in constraints are specified as an atom:
|
|
=== Custom constraints
|
|
=== Custom constraints
|
|
|
|
|
|
Custom constraints are specified as a fun. This fun takes
|
|
Custom constraints are specified as a fun. This fun takes
|
|
-a single argument and must return one of `true`, `{true, NewValue}`
|
|
|
|
-or `false`.
|
|
|
|
|
|
+two arguments. The first argument indicates the operation
|
|
|
|
+to be performed, and the second is the value. What the
|
|
|
|
+value is and what must be returned depends on the operation.
|
|
|
|
|
|
-`true` indicates the input is valid, `false` otherwise.
|
|
|
|
-The `{true, NewValue}` tuple is returned when the input
|
|
|
|
-is valid and the value has been converted. For example,
|
|
|
|
-the following constraint will convert the binary input
|
|
|
|
-to an integer:
|
|
|
|
|
|
+Cowboy currently defines three operations. The operation
|
|
|
|
+used for validating and converting user input is the `forward`
|
|
|
|
+operation.
|
|
|
|
|
|
[source,erlang]
|
|
[source,erlang]
|
|
----
|
|
----
|
|
-fun (Value0) when is_binary(Value0) ->
|
|
|
|
- try binary_to_integer(Value0) of
|
|
|
|
- Value -> {true, Value}
|
|
|
|
|
|
+int(forward, Value) ->
|
|
|
|
+ try
|
|
|
|
+ {ok, binary_to_integer(Value)}
|
|
catch _:_ ->
|
|
catch _:_ ->
|
|
- false
|
|
|
|
- end.
|
|
|
|
|
|
+ {error, not_an_integer}
|
|
|
|
+ end;
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+The value must be returned even if it is not converted
|
|
|
|
+by the constraint.
|
|
|
|
+
|
|
|
|
+The `reverse` operation does the opposite: it
|
|
|
|
+takes a converted value and changes it back to what the
|
|
|
|
+user input would have been.
|
|
|
|
+
|
|
|
|
+[source,erlang]
|
|
|
|
+----
|
|
|
|
+int(reverse, Value) ->
|
|
|
|
+ try
|
|
|
|
+ {ok, integer_to_binary(Value)}
|
|
|
|
+ catch _:_ ->
|
|
|
|
+ {error, not_an_integer}
|
|
|
|
+ end;
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Finally, the `format_error` operation takes an error
|
|
|
|
+returned by any other operation and returns a formatted
|
|
|
|
+human-readable error message.
|
|
|
|
+
|
|
|
|
+[source,erlang]
|
|
|
|
+----
|
|
|
|
+int(format_error, {not_an_integer, Value}) ->
|
|
|
|
+ io_lib:format("The value ~p is not an integer.", [Value]).
|
|
----
|
|
----
|
|
|
|
|
|
-Constraint functions should only crash because the programmer
|
|
|
|
-made an error when chaining constraints incorrectly (for example
|
|
|
|
-if the constraints were `[int, int]`, and not because of input.
|
|
|
|
-If the input is invalid then `false` must be returned.
|
|
|
|
|
|
+Notice that for this case you get both the error and
|
|
|
|
+the value that was given to the constraint that produced
|
|
|
|
+this error.
|
|
|
|
|
|
-In our snippet, the `is_binary/1` guard will crash only
|
|
|
|
-because of a programmer error, and the try block is there
|
|
|
|
-to ensure that we do not crash when the input is invalid.
|
|
|
|
|
|
+Cowboy will not catch exceptions coming from constraint
|
|
|
|
+functions. They should be written to not emit any exceptions.
|