It's vitally important that all data is verified on the server when it comes from an untrusted client. (Doubly so with Javascript since hacking tools are built into browsers.) So the question is whether (and how) you should reuse the validation code on the server side or write separate validation code for the UI. Each has trade-offs.
Generalize
On the surface, getting errors from server side code is easy... just an AJAX POST away. However, matching string error messages to fields is brittle. Just listing the messages under the form is not as UXified as what's expected nowadays. So in order for your server-side validation to be useful for other purposes, it has to be structured properly. For instance, your errors could have identifiers that the UI can map to specific fields or messages. Sample errors:
["UsernameTooShort", "UsernameHasInvalidCharacters"]
In this case, either of the error identifiers are probably configured to cause the username
control to light up red in the UI. You could wire up static messages in the UI to display for each of these (if present). You could send additional information with the error as needed by making it an object instead of a simple string.
[{"UsernameTooShort", "Username must be at least 8 characters."},
{"UsernameHasInvalidCharacters", "You can't use '\' in the username"}]
You could display the messages associated with these errors directly instead of static messages while still knowing which control they should apply to, by their identifiers. You could even send context-specific data for specific messages. Either way, the errors are no longer simple strings, which will require some work on the server-side, versioning awareness because changing an identifier could break clients, etc.
Specialize
Now the alternative is to keep using your existing simple errors on the server, and use different methods in the UI. This has some disadvantages compared to above (not a complete list).
- DRY - Although technically the rule of 3 will likely apply here so it may not violate DRY
- Extra work - It's probably not more work considering what you have to do to make errors reusable on the server... however, it's work spread across different tech stacks.
- Divergence - Two implementations of the same validation can diverge over time quite easily without diligence.
It also has some advantages (not a complete list):
- Can be diverged intentionally -
I have done this where I'm creating a new API and importing data which was not rigorously validated. I can't throw the data away, so it's nice to be able to make the server-side more lax to accommodate that and let the UI enforce more strict validations on updates and new data. Malicious users will still only be able to save data in no worse shape than what already exists.
- Each layer gets to validate in a way that makes sense for it. For the server it's often a binary choice of Pass/Fail (with message). For the UX, it's a bit more involved with control/style manipulation.
- Often the UI side will require extra validation code not on the server anyway due to technicalities of the platform. For example, control manipulation