Ajax Application Design
Ajax is almost exclusively a client-side paradigm. And, indeed, it is increasingly clear that we can use JavaScript in general, and Ajax in particular, to create new and interesting applications and interfaces. That said, server-side programs still have a major role to play in Web applications, including Ajax applications.
To begin with, only server-side programs can access the site's relational database. (And yes, it's theoretically possible to have JavaScript access the database directly, but that would be a security and performance nightmare.) This means everything you normally would store in a database, but want to have displayed in the browser, will need to be filtered through a server-side program. Almost any nontrivial application will thus benefit from being part of a larger Web framework, such as Zope, Ruby on Rails or even a roll-your-own system that encapsulates behavior in a set of related methods or functions. In other words, the server-side programs in an Ajax application become very specialized database query and reporting tools.
In the interests of time and space, we don't access a database this month. However, there is no way for the HTTP client to know whether the HTTP server is checking a database or returning a random result, and we will take advantage of this secrecy to fudge the lack of a database. If we decide at some point to modify our server-side program to retrieve a list of user names from a database instead of hard-coding the list in a hash, that will be just fine.
Our server-side program, check-name-exists.pl (Listing 3), is a simple CGI program written in Perl. We turn the POSTDATA parameter, which we have received from the Ajax request, and look inside it to see if we received a setting for username. If so, we then look for a match among the keys of the %usernames hash. If we find a match, it returns yes to the caller. If there is no match, it returns no.
Listing 3. check-name-exists.pl
#!/usr/local/bin/perl
use strict;
use diagnostics;
use warnings;
use CGI;
use CGI::Carp;
# Define the usernames that are taken
# (Use a hash for lookup efficiency)
my %usernames = ('abc' => 1,
'def' => 1,
'ghi' => 1,
'jkl' => 1);
# ------------------------------------------------------------
my $query = new CGI;
print $query->header("text/plain");
# Get the POST data
my $postdata = $query->param("POSTDATA");
# Get the username
my ($name, $value) = split /=/, $postdata;
my $username = '';
if ($name eq 'username')
{
$username = $value;
}
# If this username is defined, say "yes"!
if (exists $usernames{$username})
{
print "yes";
}
# Otherwise, say "no"!
else
{
print "no";
}
Notice how we use a hash, rather than an array, to store the user names. This is a hack for the sake of efficiency; the time it takes to find an array element (and see if there is a match) is proportional to the number of elements in the array. By contrast, hash key lookups take constant time, regardless of how many elements there are. In a production setting, we obviously would expect to look for user names in a database or server-side disk file, rather than a hash or an array.
This example also demonstrates one way to mock up an Ajax application while development is still taking place—create a server-side program that produces results for a very small subset of the data, simulating the full range of database queries that you might normally want to use. In this way, development on the JavaScript side of the project will not have to wait for the server-side portion to be complete, allowing for more parallelized development.
When the response arrives from the server, our callback routine, parseResponse, is invoked. As always, we wait until the readyState of our XMLHttpRequest is 4 and for the HTTP status code to be 200. At that point, we can expect one of four different responses from the server:
A yes response indicates that the user name was taken. We disable the form's submit button and display a warning. If and when the user changes the text inside of the username text field, the warning will be removed and the submit button re-enabled.
A no response indicates that the user name is available. We remove any warning that might have been placed, and enable the submit button.
An empty response might come before the yes or no, in which case we ignore it.
Finally, it's possible that our program will not behave precisely as we might expect. If this happens, we display the unexpected response that we received for debugging purposes. This is the sort of thing you would probably want to remove from production code.
Notice how we used a switch statement to look at the different possibilities. Also notice how we were able to reduce the complexity of our JavaScript code by sharing the work with the server. This is the key to a good Ajax application. Rather than having the client or the server do all of the work itself, each of them shares in the burden, doing what it can do fastest and most cleanly.
Finally, you might notice that for all of our talk about XML—it is, after all, the x in Ajax—there was a distinct lack of XML in this application. True, we used the XMLHttpRequest to send HTTP requests to the server, but what happened to the XML?
The truth is that Ajax is a great name, but it doesn't quite describe the range of options the programming paradigm provides. The HTTP response, as I indicated above, can come in any MIME type, although XML and plain text are the most common. If this application were returning a more sophisticated set of data, such as a store inventory or points for a chart, XML might be more appropriate. Another format that is gaining in popularity is JSON, which resembles Perl's “Data::Dumper” in its representation of JavaScript objects. Ajax is merely a technique for dividing the work between the client and the server; you should not feel compelled to use XML for the data transfer if it is inappropriate for the task at hand.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- RSS Feeds
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- Home, My Backup Data Center
- A Topic for Discussion - Open Source Feature-Richness?
- Dart: a New Web Programming Experience
- Developer Poll
- What's the tweeting protocol?
- May 2013 Issue of Linux Journal: Raspberry Pi
- Reply to comment | Linux Journal
54 min 2 sec ago - great post
1 hour 28 min ago - Google Docs
1 hour 51 min ago - Reply to comment | Linux Journal
6 hours 39 min ago - Reply to comment | Linux Journal
7 hours 26 min ago - Web Hosting IQ
9 hours 30 sec ago - Thanks for taking the time to
10 hours 37 min ago - Linux is good
12 hours 34 min ago - Reply to comment | Linux Journal
12 hours 52 min ago - Web Hosting IQ
13 hours 22 min ago
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.




Comments
Good article
Really good articles on ajax fundamentals. One comment I have is that it is not pointed out in Part 2 and 3 that the database access, register.pl, is still in effect. It is also easy to change check-name-exists.pl above to use similar database methods as register.pl users:
#!/usr/bin/perl
use strict;
use diagnostics;
use warnings;
use CGI;
use CGI::Carp;
use DBI;
# ------------------------------------------------------------
# # Connect to the database
# ------------------------------------------------------------
my $dbname = 'test';
my $dbuser = 'gene';
my $dbpassword = '';
my $dbh = DBI->connect("DBI:mysql:dbname=$dbname",
$dbuser, $dbpassword,
{
AutoCommit => 1, RaiseError => 1,
PrintError => 1, ChopBlanks => 1}) ||
print "Error connecting: '$DBI::errstr' ";
# Define the usernames that are taken
# (Use a hash for lookup efficiency)
#my %usernames = ('abc' => 1,
# 'def' => 1,
# 'ghi' => 1,
# 'jkl' => 1);
# ------------------------------------------------------------
my $query = new CGI;
print $query->header("text/plain");
# Get the POST data
my $postdata = $query->param("POSTDATA");
# Get the username
my ($name, $value) = split /=/, $postdata;
my $username = '';
if ($name eq 'username')
{
$username = $value;
}
my $select_sql = "SELECT COUNT(*) FROM Users WHERE username = ?";
my $select_sth = $dbh->prepare($select_sql);
$select_sth->execute($username);
my ($username_is_taken) = $select_sth->fetchrow_array();
# If this username is defined, say "yes"!
if ($username_is_taken)
{
print "yes";
}
# Otherwise, say "no"!
else
{
print "no";
}
I also change it to use onblur instead of onchange but had to pass a parameter to checkUserName():
function checkUsername(val) {
:
var username = val; //document.forms[0].username.value;
xhr.send("username=" + escape(username));