Previous input sanitization
In a previous attempt to include input sanitization to a Giraffe application, a certain issue was exposed. Sanitization handles more raw outputs than input validation. There is a need for greater care of failure paths and error handling. Both malicious and plain incorrect inputs could pass previous security checks and become the input of sanitization.
FPrimitive provides several string
functions to adapt the input before it is sent to the validation, but the problem was that all these functions need parameter checks (null
, blank) before certain functions can be run. This is both a tedious and weak code strategy. It can be easily forgotten and is also hard to maintain.
The previous attempt contained extra validation code to handle this. See the following DTO (Data-Transfer Object) as an example:
👀 Notice how the String.map
function makes sure that we can easily use the `Sanitize` functions without worrying about missing input.
Introducing sanitization computation expression
As guarding missing input is a repeated task for any input sanitization, this should be extracted, which is exactly what the new sanitize x { ... }
computation expression does. Each sanitize operation specified in the expression will only run when the input is present. This lets us focus on the task at hand.
Behind the scenes, the input x
will be handled as a string option
which means that all the remaining operations (trim_ws
, max
, ascii
, …) will be handled safely.
Because the input and output of this computation expression is the same (string
), one can easily compose them together and reuse common sanitization.
💡 The upcoming new version also has a european
sanitization function that lets you only pass in known European characters. See more on this in another blog post.
Updated Giraffe example
We can now use this new computation expression in our Giraffe application. Almost all the code is the same, except there is less to write and the sanitization process feels a lot more natural.
👀 Notice how we can directly use the sanitize
computation expression in our lens map without any guards. Due to the highly composable Aether lenses, we can easily add more mapping functions that do sanitization for any other input properties.
Conclusion
It is great to see how computation expressions help as a kind of ‘builder pattern’. A specification expression to build op input validations already existed, but now there is also an input sanitization expression that lets you build up complex functions with ease.
F# is highly composable and reusable. Just look at how these different packages (Giraffe, Aether, FPrimitive) can work together with no extra code. Code quality is assured when embracing F#.
Thanks for reading!
Stijn
Subscribe to our RSS feed