Building a Tangelo Web Application from Scratch

This tutorial will go through the steps of building a working, albeit simple, Tangelo application from the ground up. Most Tangelo applications consist of (at least) three parts: an HTML document presenting the form of the application as a web page, a JavaScript file to drive dynamic content and behavior within the web page, and a Python service to perform serverside processing. The tutorial application will have one of each to demonstrate how they will fit together.

String Reverser

The tutorial application will be a string reverser. The user will see a form where a word can be entered, and a button to submit the word. The word will then make a trip to the server, where it will be reversed and returned to the client. The reversed word will then be displayed in the web page.

Preparing the Stage

Tangelo will need to be running in order for the application to work. The quickstart instructions will be sufficient (see Getting Started):

tangelo

This should launch Tangelo on localhost, port 8080 (also known as http://localhost:8080/).

First we need a place to put the files for the application. We will serve the application out of a specialized directory to contain several Tangelo applications. It is a good practice to house each application in its own subdirectory - this keeps things organized, and allows for easy development of web applications in source control systems such as GitHub:

cd ~
mkdir tangelo_apps
cd tangelo_apps
mkdir reverser

Next, we need to serve this directory to the web. We’d also like to be able to see the directory contents and Python source as we edit our application, since we’re in “developer mode”:

tangelo --list-dir --show-py

By default, Tangelo serves files from the current directory. It would also be possible to use the web root option by adding --root ~/tangelo_apps to make the desired root directory explicit.

Visiting http://localhost:8080/reverser in a web browser should at this point show you a directory listing of no entries. Let’s fix that by creating some content.

HTML

The first step is to create a web page. In a text editor, open a file called index.html and copy in the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<title>Reverser</title>

<!-- Boilerplate JavaScript -->
<script src=http://code.jquery.com/jquery-1.11.0.min.js></script>
<script src=/js/tangelo.js></script>

<!-- The app's JavaScript -->
<script src=myapp.js></script>

<!-- A form to submit the text -->
<h2>Reverser</h2>
<div class=form-inline>
    <input id=text type=text>
    <button id=go class="btn btn-class">Go</a>
</div>

<!-- A place to show the output -->
<div id=output></div>

This is a very simple page, containing a text field (with ID text), a button (ID go), and an empty div element (ID output). Feel free to reload the page in your browser to see if everything worked properly.

Next we need to attach some behaviors to these elements.

JavaScript

We want to be able to read the text from the input element, send it to the server, and do something with the result. We would like to do this whenever the “Go” button is clicked. The JavaScript to accomplish this follows - place this in a file named myapp.js (to reflect the script tag in line 9 of index.html):

1
2
3
4
5
6
7
8
$(function () {
    $("#go").click(function () {
        var text = $("#text").val();
        $.getJSON("myservice?text=" + encodeURIComponent(text), function (data) {
            $("#output").text(data.reversed);
        });
    });
});

Several things are happening in this short bit of code, so let’s examine them one by one. Line 1 simply makes use of the jQuery $() function, which takes a single argument: a function to invoke with no arguments when the page content is loaded and ready.

Line 2 uses the “CSS selector” variant of the $() function to select an element by ID - in this case, the “go” button - and attach a behavior to its “click” callback.

Line 3 - the first line of the function executed on button click - causes the contents of of the text input field to be read out into the variable text.

Line 4 uses the jQuery convenience function $.getJSON() to initiate an ajax request to the URL http://localhost:8080/reverser/myservice, passing in the text field contents as a query argument. When the server has a response prepared, the function passed as the second argument to $.getJSON() will be called, with the response as the argument.

Line 5 makes use of this response data to place some text in the blank div. Because $.getJSON() converts the server response to a JSON object automatically, we can simply get the reversed word we are looking for in data.reversed. The output div in the webpage should now be displaying the reversed word.

The final component of this application is the server side processing itself, the service named myservice.

Python

The Python web service will perform a reversal of its input. The following Python code accomplishes this (save it in a file named myservice.py, again, to reflect the usage of that name in the myapp.js above):

def run(text=""):
    return {"reversed": text[::-1]}

This short Python function uses a terse array idiom to reverse the order of the letters in a string. Note that a string goes into this function from the client (i.e., the call to $.getJSON is line 4 of myapp.js), and a Python dict comes out. The dict is automatically converted to JSON-encoded text, which the $.getJSON() function automatically converts to a JavaScript object, which is finally passed to the anonymous function on line 4 of myapp.js.

Tying it All Together

The application is now complete. Once more refresh the page at http://localhost:8080/reverser/, type in your favorite word, and click the “Go” button. If all goes well, you should see your favorite word, reversed, below the text input field!

Discussion

Of course, we did not need to bring the server into this particular example, since JavaScript is perfectly suited to reversing words should the need arise. However, this example was meant to demonstrate how the three pieces - content, dynamic clientside behavior, and serverside processing - come together to implement a full, working web application.

Now imagine that instead of reversing the word, you wanted to use the word as a search index in a database, or to direct the construction of a complex object, or to kick off a large, parallel processing job on a computation engine, or that you simply want to use some Python library that has no equivalent in the JavaScript world. Each of these cases represents some action that is difficult or impossible to achieve using clientside JavaScript. By writing Tangelo web services you can enrich your application by bringing in the versatility and power of Python and its libraries.