Hacker News new | ask | show | jobs
by pphysch 1147 days ago
Client side validation is for UX.

Server side validation is for security, correctness, etc.

They are different features that require different code. Blending the two is asking for bugs and vulnerabilities and unnecessary toil.

The real reason that SPAs arose is user analytics.

6 comments

I don't understand why that should be the case. There are a lot of checks that end up needing to be repeated twice with no change in logic (e.g., username length needs to be validated on both ends).
There are two things that engineers tend to neglect about validation experiences:

1) When you run the validation has a huge impact on UX. A field should not be marked as invalid until a blur event, and after that it should be revalidated on every keystroke. It drives people crazy when we show them a red input with an error message simply because they haven't finished typing their email address yet, or when we continue to show the error after the problem has been fixed because they haven't resubmitted the form yet.

2) Client side validation rules do occasionally diverge from server side validation rules. Requiring a phone number can be A/B tested, for example.

Even if you’re not A/B testing you’re going to have some validations that only happen server-side because they require access to resources the client doesn’t have, but I don’t see either of these points as arguments against sharing the validators that can be.
I agree. These points are arguments against the philosophy of HTMX which asserts that you can get everything you need without client-side logic.

To be fair, I'm also not a fan of bloated libraries like React and Angular. I think we had it right 15-20 years ago: use the server for everything you can, and use the smallest amount of JS necessary to service your client-side needs.

> HTMX which asserts that you can get everything you need without client-side logic.

That's not true at all. HTMX extends the logical capabilities of HTML, and _hyperscript goes even further.

It’s been a while since I did much frontend work but I actually found Angular revelatory. It makes it so easy and it’s really batteries-included.
Username length does not "need" to be validated on the client. However, it is nice for UX to enforce it there.
I think a charitable reader could infer that this is often made a requirement out of UX concerns and therefore it “needs” to be done. Do you have a substantive objection to what I said?
a requirement that is solved by setting the length on your input field?

or have we forgotten that plain hold HTML can validate much of this for us with no JS of any type required?

There are limitations to that, as you well know, since you hedged with “much of.” And this is, again, a nitpick around the edges and not really a comment that addresses my main point.
Input validation checks are such a small part of the codebase; it feels weird that it would dictate the choice of a server-side programming language. Server-side python is very capable of checking the length of a string, for example.

One challenge is that you've got to keep the server-side and client-side validations in sync, so if you'd like to increase the max length of an input, all the checks need to be updated. Ideally, you'd have a single source of truth that both front-end and back-ends are built from. That's easier if they use the same language, but it's not a requirement. You'll also probably want to deploy new back-end code and front-end code at the same time, so just using JS for both sides doesn't magically fix the synchronization concerns.

One idea is to write a spec for your input, then all your input validation can compare the actual input against the spec. Stuff like JSON schema can help here if you want to write your own. Or even older: XML schemas. Both front-end and back-end would use the same spec, so the languages you pick would no longer matter. The typical things you'd want to check (length, allowed characters, regex, options, etc.) should work well as a spec.

It's also not the only place this type of duplication is seen: you'll often have input validation checks run both in the server-side code and as database constraint checks. Django solves that issue with models, for example. This can be quite efficient: if I have a <select> in my HTML and I want to add an option, I can add the option to my Django model and the server-side rendered HTML will now have the new option (via Django's select widget). No model synchronization needed.

As others mention, you may want to write additional validations for the client-side or for the server-side, as the sorts of things you should validate at either end can be different. Those can be written in whichever language you've chosen as you're only going to write those in one place.

I don’t disagree that if this is your sole reason for picking a language it is not a great one. But it is a benefit nevertheless. And obviously we can express more complex rules in a full-on programming language.
A possible solution could be what ASP.NET does where you can just set the validation rules in the backend and you get the client side one too, the magic is done by jQuery unobstrusive validation. Of course something a bit more up to date than jQuery would be ideal but you got the gist.

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/val...

You shouldn't have to wait until you submit something to get feedback on it. It's poor UX.

Frontend and backend validations are also different. Frontend is more about shape and type. Backend is content and constraints.

Right, you shouldn’t, but that means writing them twice. One of the selling points of backend JavaScript is the same validation code can run on both ends (obviously any validator that needs to check, e.g., uniqueness in a database won’t work).
Frontend and backend validation are usually not the same though. You won't be writing the same thing twice, you'll be writing different validations for each.
I think the frontend validations will, most of the time, be a subset of the backend ones, with many shared validation points.
Yes, exactly!

I’ve several times been in the position of writing a new UI for an existing API. You find yourself wanting to validate stuff before the user hits “submit”, because hiding errors until after submitting is terrible UX; and to do that, you find yourself digging into the server code to figure out the validation logic, and duplicating it.

And then years or months later the code gets out of sync, and the client is enforcing all sorts of constraints that aren’t needed on the server any more! Not good.

> It's poor UX.

It's not as easy as that. Showing validation while people are editing can be even worse, especially for less-technically able users or people using assistive technology.

Having an announcement tell you your password isn't sufficiently complex when you're typing in the second letter might not be bad for us, but how does that work for a screen reader?

That seems like it’s resolved by waiting for a focus change event.
Not really. GOV.UK Design System team have done lots of research into this and their guidance says:

> Generally speaking, avoid validating the information in a field before the user has finished entering it. This sort of validation can cause problems - especially for users who type more slowly

https://design-system.service.gov.uk/patterns/validation/

Not seeing how that’s inconsistent with evaluating when the user goes to the next field.
> The real reason that SPAs arose is user analytics.

Can you go into that a bit? I don't really understand what you mean.

HTML gives very limited tools for tracking what a (potentially JS-less) user is doing. There are various tricks, like "link shorteners" and "magic pixels" that allow some tracking.

But if you want advanced tracking, like tracking what a user is focusing on at a particular instant, you need to wrap the whole document in a lot of JS.

SPA frameworks came out of AdTech companies like Meta, and I assure you it wasn't because they had limited engineering resources.

I can imagine that Facebook and Google liked the way Angular and React allowed for more advanced tracking. But it seems like you're giving too much weight to that as a primary cause.

From my memory of working through this time, it was driven more by UX designers wanting to have ever more "AJAXy" interfaces. I did a lot of freelancing for design agencies 2006 - 2016, and they all wanted these "reactive" interfaces, but building these with jQuery or vanilla JS was a nightmare. So frameworks like JavaScript MVC, Backbone.js, SproutCore, Ember.js were all popping up offering better ways of achieving it. React, Vue and Angular all evolved out of that ecosystem.

That’s a good and logical story, but it doesn’t match the reality in my experience.

Companies use SPA frameworks for the same reason they use native apps, to make a “richer”, more responsive, more full-featured UI.

Analytics is typically done in a separate layer by a separate team, usually via Google Tag Manager. There might be a GA plugin for your UI framework, but it can work equally well with plain HTML. GA does use a bunch of client-side JS, yes, but it’s not really a framework you use on the client side, it’s just a switch you flip to turn on the data hose.

In my experience, trying to add analytics cleanly to clientside UI code is a complete pain. Trying to keep the analytics schema in sync as the UI evolves is really hard, and UI developers generally find analytics work tedious and/or objectionable and hate doing it.

Google Tag Manager is the big story in adtech, and I think it comes from and inhabits a completely different world from Angular, React etc.

You can do all that with vanilla html. Cursor tracking, scroll tracking. With HTMLX it makes it trivial.

React isnt a SPA framework. It’s a component framework. It has no router or even state management. ExtJs is an Mvc framework in JavaScript and can be used to create a full spa app without additional libraries. It also came out in 2007. There is also ember that also predates react and is another mvc framework by the people who did rails.

This is not correct. SPAs and web components were pioneered by Google with the introduction of Angular. Later, Vue was invented by a previous Google employee who had worked on Angular. Finally, Facebook came up with React (it's a "reaction" to Angular) because they could not be seen using a Google product.

If anything, SPAs make metrics harder because they hide the real behavior of the page in local JS/TS code and don't surface as much or any information in the URL. Also, fewer server interactions means fewer opportunities to capture user behavior or affect it at the server level.

A lot of misconceptions here.

Google is an AdTech company par excellence.

You don't need to do hacky URL tracking with SPAs. That's the point.

>Also, fewer server interactions means fewer opportunities to capture user behavior or affect it at the server level.

SPAs certainly do not have "fewer server interactions". What do you think an API call is?

"React" comes from "reactive web app", not "reaction to a competitor's product".

I work with SPAs with API calls every day. It definitely reduces the server interactions over computing everything on that side, and it gives fewer points of contact with the server about the user's behavior. For example, many clicks and other actions will not result in any server contact at all.

I'm aware that they call it "reactive" but I'll stick with my rationale. There is no way they would use a Google product like that.

I... don't believe you? Like looking at the network request of any SPA I've ever seen there's just tons of requests for even simple page loads. One for main content, one for profiles, one for comments, etc.

In theory stuff like graphql helps but in the reality I'm living in SPA's hit multiple endpoints to get render even simple pages.

An enterprise React app I am currently working with takes about 50 requests to fully render the app post-login. Switching to another view (no reload) takes another few dozen. That's a lot of "server interactions", pretty standard for SPAs, but YMMV.
your timeline is a bit off. facebook had react in production (mid-late 11) less than a year after angularjs went public, open-sourced it 18-24 months later (early 13), then evan started working on vue a few months after that (mid 13) and released early the following year
Thank you. I stand corrected.
React was significantly better than Angular (version 1).

Please don't pretend it was merely NIH syndrome that led to its creation.

I mean, they also came out with 'flow' after MS came out with TypeScript... I def don't want to think it was NIH syndrome, but it smells fishy.
But that would suffice! Facebook does not use any platforms from people who might compete with them. Why would they?
Fact check: Evan didn't work on angular.js, as in he was a user, not a contributor.

Source: Vue.js documentary

But if you don't blend the two, then you have a DRY violation. Someone should only have a say a field (column) is required in one and only one place, for example. The framework should take care of the details of making sure both the client and the server check.

I myself would like to see a data-dictionary-driven app framework. Code annotations on "class models" are hard to read and too static.

DRY has its limitations. Client-server boundary is a good candidate for such a limit.
that seems like an easy way for validation logic between the two to fall out of sync. Limits want to be enforced on the back end, definitely, but if the frontend also does the same validation the user experience is better, so you want to do some there as well (eg blank username does not need to do the slow round trip to the server). Through the magic of using JavaScript on both ends, the exact same bit of code can, with a bit of work, be used on both the front and the back end, so you can get the best of both worlds.
I actually tend to think of it to add feature degradation and handle micro service issues. It always seemed better to have the client manage that, and more graceful.
The number of SPAs that implement their own timeouts when I'm stuck on 2G networks is non-zero and incredibly annoying. The network socket has a timeout function, just because you 'time out' doesn't mean the network timed out, that data is still being transferred and retrying just makes it worse.
I don't understand how spa is different than vanilla web app in terms of user analytics? A beacon is a beacon. Whether its img tag with a 1x1 transparent gif or an ajax call.

Also validation is usually built on both client and server for the same things. Like if you have a password complexity validation. Its both on UX and the server otherwise it will be a very terrible UX experience.

A SPA can track the mouse cursor, as well as stealing form content that was left unsubmitted.
an MPA can use javascript that does exactly the same.
You don’t even need JavaScript. CSS has Hover attribute and you can use it to fire beacons.
Htmlx has a type ahead attribute that you can add to form elements and send the contents to an endpoint without the user explicit submitting the form.
I have never heard this before. Can you elaborate on the differences? What do you validate on the client side that you don't on the server and vice versa?
Some validations require capabilities that you don't want/need the client to have.

There are also validations that can improve UX but aren't meaningful on the server. Like a "password strength meter", or "caps lock is on".

Religiously deploying the same validations to client and server can be done, but it misses the point that the former is untrusted and just for UX. And will involve a lot of extra engineering and unnecessary coupling.

I'm not sure adding a meter value output to the server side check to use it in both places is really more engineering work. Writing separate checks on the client and server side seems much more likely to create headache and extra work.

That said, I could definitely see additional checks being done server side. One example would be actually checking the address database to see if service is available in the entered address. On the other hand, there really isn't any waste here either. I.e. just because you write the validation in server side JS doesn't mean you MUST therefore deploy and use it in the client side JS as well, it just means you never need to worry about writing the same check twice.

You misunderstand: the server only cares if your password is valid (boolean), not if it is "almost valid (0.7 strength)".
I understand the argument I just disagree that having a separate "bool isPasswordValid()" and "float isPasswordValid()" (really probably something that returns what's not valid with the score) function is in any way simpler than a single function used on both sides. Sure, the server may not care about the strength level but if you need to write that calculation for the client side anyways then how are you saving any engineering work by writing a 2nd validation function on the server side instead of just ignoring the extra info in the one that already exists?
In this situation code for a good strength meter is going to be an order of magnitude or two more complicated than the boolean validity check. Porting 50x as much code to the server is significantly worse than having two versions or having one shared function and one non-shared function.
I see, I have never implemented those types of validations. We do religiously deploy the same validation on client and server to explicitly avoid the mismatch of client/server validation. Having the client submit "valid" input only to have server reject it is something we have run into. Having only client side validation is something I have never run into.

Also, in my opinion things like you suggest you shouldn't do. A password strength metre is only going to give attackers hints at the passwords you have in your system. And I have not see a caps lock on warning in forever. The only password validation we do is the length which is pretty easy to validate on client and server.

> A password strength metre is only going to give attackers hints at the passwords you have in your system

No, it's not. A password strength meter just shows you the randomness of an input password, it doesn't have anything to do with passwords already in the system.

I'd agree with both takes on that it depends on the meter. Ones which truly approximate password entropy work like you say, however, for some reason, the most common use of such meters is to show how many dartboard requirements you've met while ignoring the actual complexity. When this common approach is used you combine "password must be 8 characters or more" with things like "password must have a number, symbol of ${group}, and capital letter" and the average password complexity is actually made worse for a given length due to pigeonholing.

In the full picture though, in terms of UI/UX, the meter seems like only a downside. In the dartboard use case it's great because it displays what's still needed in terms users work and think with signalling e.g. "you still need a number, otherwise you're all set". People don't really think in bits of entropy though so ll that really is being signaled by either a meter or a normal failed validation hint is "more complexity and/or length needed".

There may be good cases for using a meter while simultaneously implementing good password requirement policy I'm not thinking of though.

If you Google 'password strength' the first result is https://www.passwordmonster.com/

This works like I described, it don't show 'dartboard requirements', only entropy. I think you've misunderstood what a password strength checker is. It's definitionally not a checklist like 'You need an uppercase letter, a lowercase letter, a number, a special character'. It's a tool which measures the strength i.e. the randomness or entropy of the password.

Everything has to be validated on the server side simply for security reasons. Even if you do all validation on the client side, which prevents the users submitting a form with invalid data, an attacker can work around that. e.g. submitting the form with valid data, but intercepting the request and modifying the values there. Or simply just using curl with malicious/invalid data.

You still need the client side validation for UX. The regular users needs to know if they messed up someting in the form. Also it's a much better UX if it's done on the client side, without the need to send an async request for validations.

Yeah but that doesn't answer why you can't share validators between the backend and the frontend if both are written in the same language.
Because HTML form validation is a built-in native feature of HTML, and it's integrated in the browser:

    <input type="email" required placeholder="Please enter your email address">
Constantly reinventing the wheel in every app is silly.
These validators are rather limited and you’ll end up needing JavaScript for any Web app with anything beyond the simplest requirements.
They're limited in some ways but they're just about powerful enough to do almost everything you'd need or want to do client-side without making a network request. In my opinion it doesn't make sense to try to fit in tons of complex validation logic in the frontend.
Client side validations predominately drive user experiences.

Server side validations predominately enforce business constraints.

If you mix the concerns, either your UX suffers (latency) or the data suffers (consistency, correctness).