Web-App Architecture Tutorial: Synchronous vs AJAX
A tutorial showcasing the differences between the two web-application models.
“AJAX?? Synchronous?? I just want to submit this form man!” — my friend Elton yelled as he was slamming his head on a desk trying to create a user sign-up form for his new web-application project.
What is AJAX? Who is Elton? Why was he slamming his head on a desk?
A slight bit of context, I am currently a BCIT student in the BTech program, where we are used to writing all kinds of different host and network based intrusion and defence applications. Client-server, we can all do..but for the majority of us, web-applications are a whole new ball game.
Which is, hopefully, where I come in — as the village javascript and web-application fanatic, so here is a (larger than I expected)tutorial using node.js, express and jQuery on how the two different web-application models work.
Getting ready for the evening
Situation: We’re building a new web-application and we want to sign up users.
Mission: Build a user-registration component for a web-application that showcases both models.
Deliverables / Components:
- A simple and light weight express web-server running on Node.js.
- A sign-up page which has the sign-up form.
- A post-sign-up page which displays upon sucessful sign-up.
- A users page which displays all currently signed up users.
Set-Up:
- Ensure you have NodeJS installed.
- Download the starter project below.
- Change into the directory and run ‘npm install’ to install all the required packages.
Starter Project:
https://github.com/tratnayake/syncvsajax-starter
FINAL Product:
https://github.com/tratnayake/syncvsajax-final
Appetizers:
The rest of the article will go into detail about how each model works, but to provide you a base of information to refer to through out the tutorial, here’s a few things to know before we begin:
- There are two models, Synchronous (a.k.a “Classic”) & Asynchronous (a.k.a AJAX which means “Asynchronous Javascript and XML)
- The diagram that best describes them is below. Refer to it as we go through each model in detail.
First Course — Synchronous.
This is the “old” way of doing things. Think early websites. You fill out a form, it get sent to the web-server, and a new page is sent back to you.
Analogy: You need to submit some information, or get some information from a government office (i.e. ICBC, or the American Equivalent; the DMV). It’s like 1965 so you have to physically go to the the counter and submit your whole paper form. After they have all the information, they give you back another paper form.
- Let’s set up the project.
First ensure that you have all the required plugins installed. In the main directory*, run npm install (IMPORTANT: This is needed to install express)
*Main Directory = The top level directory that contains the bin, node_modules, public, routes, views folders.
Then install all the front-end dependancies (i.e. Bootstrap) by changing directory into: /public and running bower install. (IMPORTANT. This is required to use bootstrap. If your UI looks pre 1999, and if your console is showing 404’s not being able to find boootstarp core files, this is probably why)
Finally, let’s spin up the server and see our web-app! Change into the main directory and type: npm start
Now if you visit http://localhost:3000, you should see the following.
Creating the sign-up form.
Let’s go ahead and create a sign-up form shall we? This is what will be shown when a user visits http://localhost:3000/signup-sync.
First thing’s first is to create the sign up page. To do this, we must do the following:
- Add a route in the routes/index.ejs file. This tl:dr tells Express what to do when it gets a request for /signup-sync. Add the following code:
2. Create the actual sign-up page inside the /views folder as signup-sync.ejs
- What is .ejs? ejs stands for embeddable javascript. Think of it as the equivalent of the ECHO for PHP which allows you to embed javascript and content inside html. For all intents and purposes, think of ejs as just special html files for now.
Paste the following code in:
Now stop the running server (Ctrl +C) and start it up again: npm start and head over to http://localhost:3000/signup-sync
What have we done here?
- Created a sign-up form that takes in a username, email and password.
2. Made sure that the form uses some basic client-side html5 validation. i.e.
means that the form is expecting this field to have a string that matches an email format, and if it doesn’t, will raise an error before submitting.
3. IMPORTANT: Created a form that POST’s the data to /submit-registration-sync. As noted here:
and ultimately with:
because we haven’t built anything to handle it yet.
So what’s actually taking place here?
We’re saying that when someone submits this form, send a POST request to /submit-registration-sync.
What is POST? POST is one of the four (common) methods possible in HTTP (the protocol that is the base for all web communications on the internet). The other methods are: GET, PUT, and PATCH. (Actual spec can be found here)
For example, GET’s are the bulk of the internet. When you click on a link to this article on medium, your browser initiates a GET request to https://medium.com/p/9d01869dc97e/edit and the response will contain the html of this post.
POST’s are the method that is used to send data.
Don’t believe me?
Let’s try this out.
Handling the posted data.
- We’re getting a 404 when the form posts right now because there’s nothing to handle it. So..LETS HANDLE IT! Inside the /routes/index.js, add the following snippet:
2. Now lets see if our form posts! Restart the server (Ctrl+C, npm start) then submit some test data in the form and check your console.
As you can see here, the form submitted the form data to the server.
Store user in database.
We should also probably “store” the user in our “database”. In this case, we are using a simple .json file, and we will do so by adding the following lines:
So now when we restart the server and re submit the form, we can see the following:
And if we check inside the database.json file:
Great success!
We’re still not done though. We might notice that to the end-user, they’re still seeing the sign-in page with:
This is because the server hasn’t responded with anything yet. How rude.
Lets change that.
Send back the successful registration page.
First we need to build a successful registration page. Inside /views, create a page called signup-successful-sync.ejs with the following code:
Now, we need to ensure that the user is sent this page once they’ve sent the form.
To do that, we need to add some more code to the routes/index.js.
Which if we now try (remember to restart your server), we get the following after submitting:
Great!
Synchronous Data Retrieval
Now to the final synchronous feature, show us a list of all the currently signed up users.
The story is this:
“If someone accesses http://localhost:3000/users-sync , we want to show them list of currently signed up users!”
- So, lets start off by creating a route for that. In this route, we want to query the database to get all the users, and then feed it into the users-sync view.
2. Next, lets create the actual view itself in file /views/users-sync.ejs:
And after restarting and heading to http://localhost:3000/users-sync, we should see a table of all our users!
Voila. All requirements met using the synchronous model.
So what do we know now?
Using the synchronous model means that the whole “page” is sent to the server, and another page is also sent back from the server.
So why don’t we just do everything synchronously?
Because, (1) it’s expensive. A whole page needs to be sent and received. That should be okay for people browsing your web-app from a desktop, but what about those using a phone? That’s a lot of $$ in data.
(2) Makes the interactions very rigid. There’s only two states, either you’re sending or receiving. This would make an app like Twitter almost impossible to use because it would require constant refreshes:
The solution? AJAX.
Second Course — AJAX (Asynchronous JavaScript and XML)
Think back to that diagram I posted in the beginning:
AJAX helps us to solve these two problems in the following ways:
- Expense.
Instead of sending whole pages back and forth, one can send data back and forth, and have the page display that data. (Think about a tweet). Specifically, most data is usually sent back and forth in JSON (Javascript Object Notation) or XML (not really anymore). This means that the back-end can merely be responsible for sending and receiving JSON, and the task of presenting content be off-loaded to the client.
Actually, that’s exactly how most SPA’s (Single Page Apps) and phone-apps work. The views are usually stored on the phone and it liases with the server to update and get updates.
2. Fluidity.
Using that example of twitter, instead of having your page refresh every 10 seconds to check if there are updates, JavaScript running inside the page can periodically check with the server to see if there are any new tweets, and if there are: fetch them and update the view.
Analogy: You need to submit some information, or get some information from a government office (i.e. ICBC, or the American Equivalent; the DMV). It’s like 1995 so faxes now exist. Instead of driving all the way down to the government office, you rip off a piece your document that you need to send in and give it to the receptionist. They fax it to the office, and you get a reply. You cut out reply and paste it on your original document.
So lets get this started, asynchronous style.
jQuery
This portion of the web-app will be using jQuery quite heavily.
Creating The Sign-Up Form
Alright, so first up. We’re going to create another sign-up form, but this time, to prove that they could be used externally (i.e. a phone running the html page). we will be creating it as purely an .html file.
So in the /public/ directory, create a signup-async.html file. Since we’re not dynamically generating the page, it will have to load the header, footer, and dependencies itself.
Some things to note:
- There is no more method or action in the form.
- The submit button has become just type=button instead of type=submit.
This is because we will handle the form submission completely via client-side javascript.
Next lets create the route to show users this page when they venture to: http://localhost:3000/signup-async
This tells the router to grab the signup-async.html file from public / .
So if we venture to that page, we are met with a replica of the synchronous sign in page.
Submit the form.
Now to get to work on submitting the form. As I mentioned before, we’ve taken out the method and action for the form. So how does it send data to the back-end?
Through jQuery. The jQuery code goes inside the empty script tags inside the signup-async.html.
And here’s how it’s done, specifically with a side by side:
Okay, so what’s happening here?
- Our javascript as soon as the html has been loaded (on ready). It then latches onto the elements with those ID’s.
- Once the form’s submit button has been clicked, it immediately stops it from running it’s HTML5 submit. (Why? So that we can submit ourselves).
- The jQuery’s post function takes in 3 values, first the URL to where we’re posting the data to, the second is the actual data we’re posting in JSON, and third is the function to handle the response from the server.
And if we actually run it, we can see that it seems to work.
Note: I recommend that when working with client-side javascript that you make use of the console found in all the developer tools of most browsers. In Chrome, it’s just right-clicking and hitting “Inspect element”.
Handling the posted data.
Now on the server side, we must create a route to handle the data. This is to test if it’s actually working.
Which when we run, get this:
Now storing it in the database is simply the same as we did before, however this time, instead of sending a page to the client ourselves, we merely send them back a response and allow them to decide what to do.
Which if we test, we see:
Submission Success
As you can see, now on the client side we get a notification on whether it was successful or not. With this information, the client-side can decide what to do next.
This all happens in this section:
Perhaps we will re-direct to the sign-up successful page? If we want to do that, we can simply use jquery to do:
window.location.replace("http://NEWURLHERE");
But..hey, we’re using jQuery! Why not do some DOM manipulation?
Remember how we talked about a “fluid” experience? What if we could show the success message INSTANTLY instead of refreshing and loading a new page?
Well, we can!
First we’ll make the success message on the same page underneath our form like so:
Now obviously we don’t want this shown until we get the success message back, so we’ll need to hide it.
Finally, if the sign-up is successful, we want t to hide the form, and display the success message, and inject the username into the success message.
Success!
Right there we have demonstrated how jQuery and AJAX can be used to send data, receive data and also do DOM manipulation, all without sending whole pages back and forth.
Asynchronous Data Retrieval.
Now it’s been a long journey, but we’re not done yet. The last thing we need to do is get a list of currently signed up users.
In the Synchronous version, we had to refresh the page and retrieve a whole new page to see if there were any new users. If there weren’t, well that’s a completely wasted page load.
Before we create the view, we’re going to handle the back-end first.
By now you should be getting better at understanding the code, and if you figured that this responds to a GET to the http://localhost:3000/users-async endpoint with a list of users, you’re right!
We can test this without even writing any front-end code by using a wonderful tool called Postman ( chrome extension).
Perfect.
Essentially, what we’ve done at this point is created a REST API endpoint. Now anyone from any device can query yoursite/users-async and get a list of users. Then, each device can display that data differently.
Which is what we’re going to do now.
Display the users.
To create the page that will display the users, first we must create a route.
Now to create the page itself.
You will notice that we have no EJS in this page, and the table merely contains the headers only. We will populate all the rows manually.
First things first, on first run, we need to fetch all the users! To do this, we use AJAX and a GET.
What this code does is hit the API to get a list of users in JSON. Then with the result, iterates through the users and appends to the table.
Now, here’s where the cool part of AJAX comes in. To demonstrate how we can make requests and update data without loading the page, lets create a button that fetches users:
And finally, we need to merely handle the button click, and have it invoke that getUsers() method we created earlier.
And voila! Now we have a button that will fetch the users from the api whenever it is clicked without needing to re-render a whole new page.
With this in mind, it’s not a stretch to imagine how you can use jquery and javascript to periodically request (poll) the API for changes.
Dessert
And there you have it folks. A small tutorial describing how the synchronous and asynchronous web-application models work.
The synchronous approach has largely fallen out of favour due to the performance benefits that are afforded via AJAX, and this is what has led to the rise of mobile applications as well as the use of the REST architecture and micro-services.
Again: The final product can be found here in case some of my code doesnt work according to the tutorial:
https://github.com/tratnayake/syncvsajax-final
I hope you’ve gotten something from my tutorial, and if you have any questions, please feel free to tweet me at @tratnayake.
Kudos goes to and references:
http://adaptivepath.org/ideas/ajax-new-approach-web-applications/