Form Validations

13 Jun 2024 - Ben

When my front end is decoupled from my backend via JSON API, how does my front end know what kind of validation logic my backend does on the data I provide it? Usually, it doesn’t! How do I communicate what is a valid input to my user?

I won’t lie, typically I just recreate the validation logic in both places. It isn’t very DRY, and it’s a pain to change. My backend is even in Javascript, so you’d think it’d be easier to share logic! But the server and browser are different places, so how do I communcate that a date picker can only be from yesterday to next month? In current form, the front end would “know” the requirement and the html produced would be:

<input type="date" min="2024-02-14" max="2024-03-15" name="reservation-date">

Then the backend would have some validation logic that checked that requirement again. A naive example would look like:

reservationDate > "2024-02-14" && reservationDate < "2024-03-15"

If the requirement changed to now allow 2 months into the future, which would you change first? I would relax the backend validation to the new requirement, then the front end. 2 changes in 2 codebases with 2 different deployments. This case is simple too, since the change is simple. But I still can’t relax the front end requirement first, the backend would complain even though it looks like a date I can choose.

Server Driven Architecture

What if I could encode all the requirements and validations into a response, sent by the server, that my front end could generate the right control, with all the right validations baked in? Relaxing the allowable date from 1 month to 2 months would only requirea change to my backend, no change to my front end. What does that look like in practice? If I’m using a JSON API, I might have this shape:

{
  controls: [{
    type: "date",
    min: "2024-02-14",
    max: "2024-03-15",
    name: "reservation-date"
  }]
}

But notice how similar that is to the input above?

<input type="date" min="2024-02-14" max="2024-03-15" name="reservation-date">

I’ve basically encoded all the input attributes in json! Why not save myself a step and just send the input element itself? In a web application using React, with a decoupled JSON API, sending HTML is hard and unintuitive. But if you’re already serving HTML from your backend, this should be a breeze (and likely what you’re already doing). And templating language will suffice, I like Nunjucks with Express

More complicated validations

What about when the allowable date is dynamic, maybe based on the type of reservation?

<input type="radio" name="reservation-type" value="one">
<input type="radio" name="reservation-type" value="two">
<input type="radio" name="reservation-type" value="three"

Now you front end has logic to change the date picker min/max values based on the state of the “reservation-type” checkbox. How do you code that in a Server Driven Architecture? My only answer is I don’t know; and it’s too complicated for me to think of an answer that will satisfy all permutations of the equation. So in my day job, react app, I encode the difference validations two places: react in the front end and the mutation in the backend. But in a server driven architecture, we could have an endpoint to receive the date picker and call it every time the value of reservation-type changed. If we could send html, we would just have three date pickers on the backend we could send. This is a case for HTMX; I can reuse the validation logic from my backend and any updates can all be performed in once place, the backend. I can send and receive and splice html with ease. Or if there were another serialization format my front end could understand, maybe I could use that.