Interacting with a back end server

Many web applications consist of a both a front end and a back end. The front end consists of a set of HTML pages and JavaScript code that together implement the user interface for the application. The back end is a server that stores data for the application and delivers data on demand.

Earlier in the history of HTML interactivity in HTML was implemented through the use of forms. By offering a site visitor a form to fill out, a site would provide a mechanism to customize that user's experience. The user would fill out the form and submit the form's data to a back end server for processing by clicking the form's submit button. The web server would then respond with customized content generated by software running on the server.

The first example page I have linked to above demonstrates how this works. The example implements another version of the exercise calories calculator. The difference this time around is that the example contains no JavaScript to help with the calculation. Instead, the page contains an HTML form element.

The form element starts with this tag:

<form action="https://cmsc106.net/ExerciseCalories/exercise" method="get">

Form elements exist to gather information to be submitted to a back end server for processing. That action attribute in the form element contains a URL that points to an application running on a server that will handle the processing for the form.

Let's break down that URL:

https://cmsc106.net/ExerciseCalories/exercise

The first portion of the URL, cmsc106.net, identifies the server that will do the form processing. The second part of the URL, ExerciseCalories, identifies a particular application running on the server. Since servers typically can run many different applications at the same time, we have to identify the application we want by name. The final part of the URL, exercise, identifies one of the actions that the application can carry out. The action we are accessing here does the form processing for the form we have set up.

The next thing needed to get this to work is putting input elements inside the form to gather information from the user. This form has three sets of input elements:

<select class="form-select" name="activity" id="activity">
  <option value="walking">Walking</option>
  <option value="cycling">Cycling</option>
  <option value="swimming">Swimming</option>
  <option value="running">Running</option>
</select>

<input type="text" class="form-control" name="duration" id="duration">

<input type="radio" class="btn-check" name="level" value="low" id="level-low"/>
<label for="level-low" class="btn btn-primary">Light</label>
<input type="radio" class="btn-check" name="level" value="medium" id="level-medium" checked/>
<label for="level-medium" class="btn btn-primary">Moderate</label>
<input type="radio" class="btn-check" name="level" value="high" id="level-high"/>
<label for="level-high" class="btn btn-primary">Vigorous</label>

The third set of input elements here is a set of radio buttons. The most important thing to note about these input elements is that they all have a name attribute. This is essential for form processing, since the code that does the form processing on the server will expect the browser to send it three name/value pairs with the names activity, duration, and level.

The last essential thing a form needs is a submit button to trigger the computation.

<input type="submit" value="Compute" class="btn btn-primary"/>

The submit button is just a button. What is special about it is that it triggers the form submission. When the user clicks the submit button the browser will gather the name/value pairs from the named input elements in the form and send them to the action URL for processing.

When the user submit a form for processing the back end server will use the values provided as inputs to a computational process. That could be a calculation, a database lookup, or some combination of both. When the server sends back the result of the calculation it will send it back in the form of an HTML page that the browser will then display.

AJAX and Web 2.0

The form mechanism did provide interactivity, but it was of a limited and somewhat clunky variety. Not every kind of interaction you might imaging doing on a web site fits the form processing paradigm. A further problem that arose as developers tried to build sites using forms was that the result of form processing is supposed to be an HTML page. The problem that this caused was that form processing was a task that was most often left to software developers, and software developers often did not have the expertise in HTML and CSS to make the pages delivered by the form processing software blend properly with the other pages on the site.

To more successfully implement interactivity in a web site, site developers needed a mechanism that would more cleanly separate computation from presentation. That mechanism arose eventually in the form of a JavaScript programming technique known as AJAX (Asynchronous JavaScript and XML). Here are the key aspects of the AJAX style of programming:

  1. A page developer uses JavaScript to implement interactivity by providing event handler functions linked to buttons or other page elements.
  2. When a user clicks a button, the JavaScript event handler function for that button sends a request for data to a web server.
  3. The web server responds not with an HTML page, but with data encoded in a form that is easy for JavaScript to process.
  4. The JavaScript in the page receives the data and integrates the data back into the page using DOM manipulation techniques.

The data that comes from the server can be the result of some complex computational process. The work of managing that process is left to the software developers who write the software for the server. The JavaScript developer is left with the relatively simple task of formulating the request and then integrating the result data back into the page. This arrangement is superior to the form processing paradigm, because in this arrangement each developer can concentrate on their particular areas of expertise: server developers only worry about data, while the page developer concentrates on presentation via HTML and CSS and page manipulation via DOM techniques.

The style of interactivity described above lead to a minor revolution in web development. Some of the early pioneers of this style of development, including the team that designed the web interface for GMail, were able to use these techniques to introduce an entirely new class of web applications. These new applications were a sufficiently radical departure from earlier form-based interactivity that developers attached the term "Web 2.0" to applications built using this new style of development.

JSON

When AJAX was first developed, the encoding system used to transfer data from the server to the page was XML, which is a data description language created by the World Wide Web Consortium, or W3C. (The W3C is headed up by Tim Berners-Lee, the inventor of the World Wide Web.) Getting JavaScript to play well with XML data is something of a challenge, so over time JavaScript developers went looking for an alternative scheme for encoding data. The scheme that eventually emerged as a clear favorite for AJAX development was the JavaScript Object Notation, or JSON. JSON encodes JavaScript data in the form of a text string whose structure closely mirrors the structure that JavaScript itself uses to represent data via arrays, objects, and simple data types such as numbers and text.

Here is an example of some JSON encoded data:

[{"cost":795,"iditem":8,"meal":"dinner","name":"Spaghetti Dinner"},{"cost":895,"iditem":9,"meal":"dinner","name":"Fried Chicken"},{"cost":895,"iditem":10,"meal":"dinner","name":"Stir Fry"}]

The example encodes an array containing three objects. The only difference you will see here between JSON notation and JavaScript notation is that in JSON notation all of the property names for object literals have to be enclosed in quotes.

Since JSON is so close in form to JavaScript, converting a chunk of JSON text into JavaScript data is relatively simple. In all of the examples I will be showing in this class we will use JQuery functions to do AJAX operations for us. Those functions will take care of converting our JavaScript data to and from JSON form for us automatically.

REST

One final piece of the puzzle needed to implement AJAX is a server that can deliver JSON data to us. Another technology needed to implement such a server is REST, which stands for Representational State Transfer. REST is a server architecture standard, and server developers build server applications to conform to the key aspects of the REST style.

The foundation of REST is the language that web browsers and web servers use to communicate with each other, the Hypertext Transfer Protocol, or HTTP. When a browser sends a request to a web server via HTTP the browser will ask for data via a combination of an HTTP verb (which specifies what we want to do with the data) and a URL (which identifies the data we want to act on). In the vast majority of cases browsers want to fetch a page: for that kind of interation the browser will send the GET verb followed by a URL that identifies the page the browser wants delivered.

When Tim Berners-Lee developed HTTP he envisioned something a little more complex than a system for just fetching web pages. In his original vision for the web, he imagined a system in which users could fetch web pages, edit them in a browser, and upload their edits back to a web server. To facilitate this, he provided HTTP with four different verbs.

VerbWhat it does
GETFetches data (usually a web page)
POSTUploads data to the server
PUTUpdates data on the server
DELETERemoves data from the server

In addition to accomodating a range of data operations, HTTP also offers standardized ways to transfer data. For example, when a browser sends a GET command to a server, it knows to expect data in the response. Specifically, when the response comes back it will have a body, and the requested data will appear in that body. Likewise, a POST command going to a server can have a body, and that body can contain data that we want to upload to the server.

The upshot of all of this is that HTTP was built right from the very start as a system for managing the flow of data back and forth between browsers and servers. Most of these capabilities stayed dormant for many years and were not used. Eventually, though, someone figured out how to leverage the full power of HTTP to make a data architecture based on the web and HTTP. That architecture is called REST, and it uses HTTP (verbs and URLs) along with a data representation (XML or JSON) to make a complete computing infrastructure. REST is another key element of the Web 2.0 style of programming, in that AJAX is most often used with REST based servers that offer what are known as RESTful web services.

Working with a RESTful web service

To begin to explain how REST web services work, I have set up a simple web service at cmsc106.net. This web service serves up data on menu items and orders at an imaginary cafe. This will allow us to complete the cafe ordering application from last week by fetching menu items from the server and uploading orders to it.

Interaction with a web service starts with URLs. Web services typically offer access to several related pools of data, and the data collection we want to access gets built into the URL. For example, to access information about available menu items we will be using a URL like this:

http://cmsc106.net/cafe/item

This URL consists of several components. The first component is the server we want to contact, cmsc106.net. The next part of the URL, /cafe, identifies the web application we want to interact with. Since a single server can host multiple applications, we have to identify a specific application to interact with. Finally, since a web service typically offers access to many different data collections, we have to identify the data collection through the /item part of the URL.

Once we have a properly constructed URL the web service will respond by serving up some data. In this case, the web service will respond with

[{"meal":"breakfast","iditem":1,"cost":495,"name":"Breakfast Burrito"},
{"meal":"breakfast","iditem":2,"cost":395,"name":"Oatmeal"},
{"meal":"breakfast","iditem":3,"cost":595,"name":"Two Egg Combo"},
{"meal":"lunch","iditem":4,"cost":595,"name":"Grilled Panini"},
{"meal":"lunch","iditem":5,"cost":495,"name":"Soup of the Day"},
{"meal":"lunch","iditem":6,"cost":495,"name":"Hamburger"},
{"meal":"lunch","iditem":7,"cost":495,"name":"Felafel Sandwich"},
{"meal":"dinner","iditem":8,"cost":795,"name":"Spaghetti Dinner"},
{"meal":"dinner","iditem":9,"cost":895,"name":"Fried Chicken"},
{"meal":"dinner","iditem":10,"cost":895,"name":"Stir Fry"}]

This is a JSON encoded list of menu items.

Since browsers implement GET requests any time you type a URL into their address bar, you can put the URL above into your browser to see the data that the server responds with.

Sending a GET request to a web service from JavaScript

Since we are going to be using a web service as a data source, we next need to cover how to contact the web service from a JavaScript program. We will be using the JavaScript fetch() function to do this.

The sample code below demonstrates how fetch() works in the cafe application.

// Callback function for the fetch items query
function receiveItems(data) {
  items = data;
  document.getElementById('starting').style.display = 'none';
  document.getElementById('view').style.display = '';
  displayMeal('lunch');
}

fetch('http://cmsc106.net/cafe/item')
  .then(function(response) {
    // Convert the JSON response and pass it to receiveItems
    return response.json();
  })
  .then(receiveItems);

One new aspect of fetch() as a function is that it will process the GET request asynchronously. Calling fetch() sends our request to the server at the indicated URL, but does not return any information. When the response eventually comes back from the server, fetch() will react by calling a pair of special callback function specified in the .then() calls that follow after the fetch(). The first callback function for this example receives a response object, converts JSON data from the response to JavaScript data using the json() function, and passes that JSON data to the next callback. The second callback function for this example, receiveItems, has a single parameter, data. When JQuery calls our second callback function it will pass any data that came back from the server to the callback function in that data parameter. receiveItems will take that data and assign it to the global variable items so it can be available to other parts of the application. Once the initial data for the application has arrived from the server we can hide the div that displays the 'starting up' message, show the div where the menu items get displayed, and then call the displayMeal function to fill the menu table with items.

POSTing data to the web service

At the other end of the application we will want to upload orders to the server. To do this we will POST our data to the URL http://cmsc106.net/cafe/purchase. The purchase collection contains information about orders and expects us to upload objects that have the following form:

{customer:"Joe",phone:"555-1212",items:[6,7]}

The following code shows how to do this:

// Event handler for the place order button
function placeOrder() {
  // Construct a list of id numbers for the ordered items
  var item, ids;
  ids = [];
  for(item of order)
    ids.push(item.iditem);
  // Construct the order object
  var name = document.getElementById('name').value;
  var number = document.getElementById('phone').value;
  var toPost = {customer:name,phone:number,items:ids};
  // POST it to the server
  fetch('http://cmsc106.net/cafe/purchase',{
    method:'POST',
    headers:{'Content-Type':'application/json'},
    body:JSON.stringify(toPost)
  })
  .then(function(response) {
    // Convert the JSON response and pass it to showConfirm
    return response.json();
  })
  .then(showConfirm);
}

The fetch() code in this example is a little more complex. The second parameter we pass to fetch() is a JavaScript object that specifies in more detail how to handle the request. This object tells fetch() that we are doing a POST request, not a GET and that the body of the request will contain JSON code. The body property contains the JSON code for our toPost object converted to JSON via the JSON.stringify() function.

Once again this fetch() call contains a couple of .then() calls containing callback functions. The server we are working with will respond to a successful POST to purchase by returning an order number. In this application we will use the following function as final callback for the fetch call:

// Success callback for the place order POST
function showConfirm(data) {
  document.getElementById('number').textContent = data;

  document.getElementById('order').style.display = 'none';
  document.getElementById('confirm').style.display = '';
 
}

This function places the order number in the page, hides the ordering div and shows a confirmation div where the user will see a confirmation message.