Server-side validation for auto-saving multipage form - node.js

I'm currently building out a multipage form using Flutter (frontend) and Node/Express/MongoDB/Mongoose (backend) for which I would like to implement auto-saving as the user progresses through each page (ie. clicking the next button after each page saves form data to the DB).
I have client-side validation to ensure fields are filled out and in the correct format, but I believe server-side validation is more important to implement in the event the user bypasses the client-side. I was wondering if anyone had general design ideas/processes I could implement for this idea. Some ideas I have:
I'm thinking about sending a POST/PUT request to our server after each page, but I have no way of validating the incoming data server-side unless I create over 30 schemas for each of the pages. Each page has different questions so there isn't a single common validator I can use.
Another option was having a temporary object with all the fields, and only validate the object at the very end when the user clicks 'submit,' but this is bad UX design in my mind as any error may require the user to be set back to the 1st or 2nd page which is frustrating for sure.
My main concern is validating the incoming data on the server-side as well as the client-side, but I can't seem to think of a good way to do both in a clean manner. I believe this question is language-agnostic, but I added my tech stack just in case.
Any help would be greatly appreciated :)

Related

How the check if a form data has been changed before send new changes

Im working with a OEAN stack building a sistem that users fills a form in angular, the problem is that it could happend that two users open one specific form at the same time and send the modifications after the other, resulting in the reverse of the changes made from the other user.
So i want tho check if the status of the form has changed before send the modifications and alert to the user and make him reload the form before sending his changes.
Dont know if the aproach could be made from the front (angular) or the backend (nodejs)
Thanks for the help in advance.
i, ve tryed to aproach the problem on the user profile base, but the design of the form and the data model doesnt make this a fast solution. Thats a later aproach for more quiet times.

Cakephp 3 Stripe payment form

I'm hoping someone out there can help me understand how Stripe should work with Cakephp 3.
I have a form with the Stripe payment fields and a couple of fields for my cake app. From the Stripe documentation this seems to be an acceptable way to set it up.
The HTML is fairly standard, but note how every input for sensitive
data—number, CVC, expiration, and postal code—omits the name
attribute. By omitting a name, the user-supplied data in those fields
won't be passed to your server when the form is submitted. Each
element also includes a data-stripe attribute, to be discussed later.
I'm using cakephp 3 now which doesn't seem to allow me to remove properties from the HTML generated by the form helper. I can only make the 'name' property be blank. I queried this with Stripe support and they were a little noncommittal. They are generally very good but in this instance the answer seemed to be 'better safe than sorry.'
My main question is this: does it really matter if you don't use the form helper for Stripe fields. The main benefit i can find in the cake docs is that the CSRF component will act on those fields. I am using the CSRF component throughout my app, but since the Stripe fields aren't even sent to the server the CSRF component is irrelevant. Isn't it?
Here's an excerpt from the Cakephp manual:
The CsrfComponent works by setting a cookie to the user’s browser.
When forms are created with the Cake\View\Helper\FormHelper, a hidden
field is added containing the CSRF token. During the
Controller.startup event, if the request is a POST, PUT, DELETE, PATCH
request the component will compare the request data & cookie value. If
either is missing or the two values mismatch the component will throw
aCake\Network\Exception\InvalidCsrfTokenException.
I can still use the form helper for the few fields that do get submitted to the database, and just add the Stripe fields with HTML?
Does that make sense?
Stripe support did suggest having two separate forms, one for the cake data and one for the Stripe data, but since their docs say you can add the Stripe fields to a form that gets submitted to the server that seems a bit odd.
I would really appreciate some input on this as it seems even Stripe themselves aren't sure how to structure a cakephp payment form!
Yes raw HTML appears to be the way to go.
Here's what i did.
Used the form helper to start and end the form (This means form tampering and CSRF will work for your non Stripe fields)
Added the Stripe fields within the Cake form using HTML (I haven't tested the HTML fields to see if the form tampering works on them. I'll test that later and post back)
Used the Form helper to unlock the stripeToken field so it could be added to the form without the form tampering blackholing the request.
Once i set all this up I used echo debug($_POST) in my controller to see what the form was submitting to the server and the only Stripe field that was showing up was stripeToken.
So it appears to me that this is working as it should.

ExpressJs route redirect

I have a widget for user to get information regarding books. The UX of the widget changes according to the fact that the user is logged in or not. Now I have a route for logged-in user(say, /user/getBookInfo) to get the book information(which includes sending sms n email logic). For users who are not logged-in I have created a different route(say, /public/getBookInfo), which includes some additional processing too. However retrieving the book information, sms and email logic etc is already present in '/user/getBookInfo'. I don't want to duplicate this function.
One option is call res.redirect('/user/getBookInfo') from /public/getBookInfo . However I want to avoid the redirect in this way.
So My question is How can I reuse this logic in /public/getBookInfo without using redirect??
Probably the best way in a Node.js application is to make a separate module, and put the common logic there. Then you can require the module in both routing files.

Flow of forms in Node.js and Express

Our lab makes many web experiments, all of which have a similar flow:
The user fills a form and submits. The form is validated, if it is OK then the posted values are logged and the user is sent to #2; otherwise the user is asked to fill it again.
The user answers a quiz. If the answers are correct then go to #3; otherwise fill again.
The user enters the actual experiment, which is a web-app - a chat-room, a flash game, etc. After the game is finished, go to #4.
The user fills another form and submits.
In the past I did this with JSP, but now we've moved on to NodeJS and Express, and I wonder if there is a general way to handle this and similar control-flows.
The question is very general, so in general the answer is Yes - you can do all that with node and express. Just register your routes with express (e.g. using app.get(URI, func)) and serve your dynamic and static content from node. There is ample material in the web on using express.

Best practice: How to handle concurrency of browser and website navigation

It is a well known problem to every web developer. As far as I tried to find a good solution to this problem - there was none (or at least I could not find it).
Lets assume the following:
The user does not behave, as he was expected to. The actual project I'm working in uses a navigation within the web portal. But if the user uses the browser's back button, the whole thing becomes jeoprady[?] and the result was not always predictable.
We used the struts framework and stored the back-url into forms - at some places, where we needed a back-url - this has been rendered out of this form's back-url. For there was only a singe field for this information and therefore it was not possible of going back multiple steps.
When you change the "struts-flow" - which may result in using a different form - this information will be lost.
If the user dares to put a bookmark somewhere within your webapp - this information may never have been set and again the result will again be either unpredictable or not flexible enough!
My "solution":
I was storing every navigation-relevant page the user visited onto a stack-like storage into the session. This means a navigation-path is collected and stored for later navigations.
At any page within the webapp, where back-navigations are involved I used a self-made tag which renders the stack-content into the url.
And thats it.
When this back-url was clicked, the stack has been filled with the content from the back-url clicked by the user (which holds all information from the stack once the back-link was rendered).
This is quite clear, because a click on a link is a clear state, where the web developer exactly knows, where the user "is" a this very moment - absolutely independant from whatever the user did before (e.g. hitting the browser back button multiple times). Then the navigation stack is built upon this new state.
Resumé:
It becomes clear, that this won't be the best solution. But it allows storing additional information on the stack like page parameters and some other useful stuff (further developments possible).
So, what were your solutions to this problem?
cheers,
mana
The stack solution sounds interesting, but it will probably break if the user chooses to navigate "in parallel" on different tabs or using bookmarks.
I'm afraid I don't really understand why you have to keep all this state for each user: ideally the web should follow the REST principle and be completely stateless. Therefore a single URL should identify a single resource, without having to keep the navigation history of each user.
If your web app relies heavily on AJAX, you could try to implement something like GMail (admittedly, not so easy...), where each change in the interface is reflected in a change in the page URL. Therefore each page is identified by the current URL and the user can navigate concurrently or use the back button as usual.

Resources