The key that makes this code nice is that it uses Raise at every step that can fail, instead of relying on nullable types or exceptions. It thus allows you to report errors transparently, while still being compile-time checked, and playing nicely with lambdas, coroutines, etc.
Instead of Raise<String>, you can introduce your own Domain Errors later on. The nice thing is, vs http4k's lenses, you get to have typed errors.
There are a few functions like Form.required, Form.optionalString.toIntSafe and so on that are needed for convenience, but they're reusable.
You can see the power of Raise in the Form.requiredtransform variation, which prepends the field name to the error message. That would have been harder with exceptions. Raise really shines in transforming errors, especially between different domain layers, and the String-based approach here really doesn't do it justice.
You don't need to use the Form.requiredtransform variation, which might make the code look a bit simpler. It's as simple as changing required("new-itemId") { ID(it) } to ID(required("new-itemId")), but would lose out on the formData 'new-itemId': in the error message, which your version didn't have anyways.
The last commit in the PR has error accumulation, but if you don't need that, you can simply use the first commit only (and modify the test, of course).
Raise does use exceptions under the hood, but it also plays nicely with coroutines, and mostly gets out of your way, while, I suspect, lenses wouldn't really support coroutines.
Few things:
The key that makes this code nice is that it uses
Raise
at every step that can fail, instead of relying on nullable types or exceptions. It thus allows you to report errors transparently, while still being compile-time checked, and playing nicely with lambdas, coroutines, etc.Instead of
Raise<String>
, you can introduce your own Domain Errors later on. The nice thing is, vs http4k's lenses, you get to have typed errors.There are a few functions like
Form.required
,Form.optional
String.toIntSafe
and so on that are needed for convenience, but they're reusable.You can see the power of
Raise
in theForm.required
transform
variation, which prepends the field name to the error message. That would have been harder with exceptions. Raise really shines in transforming errors, especially between different domain layers, and the String-based approach here really doesn't do it justice.You don't need to use the
Form.required
transform
variation, which might make the code look a bit simpler. It's as simple as changingrequired("new-itemId") { ID(it) }
toID(required("new-itemId"))
, but would lose out on theformData 'new-itemId':
in the error message, which your version didn't have anyways.The last commit in the PR has error accumulation, but if you don't need that, you can simply use the first commit only (and modify the test, of course).
Raise
does use exceptions under the hood, but it also plays nicely with coroutines, and mostly gets out of your way, while, I suspect, lenses wouldn't really support coroutines.