Prototype web applications with CouchDB and Bootstrap

Separate web design from database design, then glue them back together

Combine Apache CouchDB with Twitter's Bootstrap to kickstart web application development in a way that cleanly separates the presentation and database layers. CouchDB is well-known as a relaxing way to develop databases, especially for websites. On the front end, more open source toolkits are emerging for prototyping sites, and even for full deployment. Among them, the Bootstrap framework is especially useful for working up web UIs. Learn how to build on Bootstrap while you use CouchDB for persistence.

Uche Ogbuji, Partner, Zepheira, LLC

Photo of Uche OgbujiUche Ogbuji is a partner at Zepheira, LLC, a solutions firm that specializes in the next generation of web technologies. Mr. Ogbuji is the lead developer of 4Suite, an open source platform for XML, RDF, and knowledge-management applications, and its successor Akara. He is a computer engineer and writer who was born in Nigeria and lives and works in Boulder, Colorado, US. You can find more about Mr. Ogbuji at his Weblog Copia, or on Twitter.



04 June 2013

Also available in Chinese Russian Japanese

Apache CouchDB is one of a new breed of database management systems (DBMSs) within the NoSQL movement. The primary information is stored as JavaScript Object Notation (JSON) documents. CouchDB also supports more general document formats as managed attachments. What it does not support is the classic tabular data, which is queried by SQL, that ruled the DBMS world for decades. Another key characteristic of CouchDB is that all of its operations are available as simple HTTP calls, particularly in the REST (Representational State Transfer) form. This architecture makes it easy to work with CouchDB regardless of your host platform or toolkit. It also makes CouchDB a useful tool for providing a persistent back end for websites and applications.

You can find several tutorials to get you started with CouchDB for application development using its built-in JavaScript libraries and related tools such as CouchApp (see Resources). In this article I take a different approach, showing that you can prototype websites quickly by combining CouchDB with a simple, statically served website scaffold.

REST in a nutshell

REST is an architectural style for loosely coupled web applications thatrely on named resources — Uniform Resource Locators (URLs), UniformResource Identifiers (URIs), and Uniform Resource Names (URNs), forinstance — rather than messages. REST leverages aspects of the WorldWide Web's HTTP infrastructure protocol, such as GET and POST requests.

One popular, new way to rapidly set up a website's front end is Bootstrap. The Bootstrap system was developed by Twitter engineers to help tame the zoo of platforms and toolkits that they used for website development. Bootstrap provides a consistent framework for web application UIs. It makes it easy to design beautiful sites with cascading style sheets (CSS) elements for typography, forms, buttons, tables, grids, navigation, alerts, and much more. In this article, learn to kickstart the development process with Bootstrap for the front end and CouchDB for the back end — even for complex web applications.

Why not prototype entirely on the CouchDB stack?

Although many tutorials show how easy it is to develop a complete production website entirely on CouchDB, it is not advisable. Getting started that way leaves a huge temptation to cut corners and use the same approach when the site goes public. From a security and maintenance perspective, it is better to separate the database back end from the presentation front end. This article gives you various options for locking down the CouchDB instance when it goes live to secure any sensitive data. Security always requires vigilance and expertise. Because websites based on static files have been around longest, they are best understood, and their management tools are most mature.

Separating CouchDB from the website front end gives you another advantage because multiple frameworks are typical during web development:

  • The DBMS for handling data
  • The web server or content-management system
  • The web design framework

In this article I use CouchDB, Apache HTTP Server, and Bootstrap.

The personnel, skill set, and criteria for choosing technology for these layers are often varied. You want decisions for one to be loosely coupled with decisions for another. In addition to them, you have moving parts such as content-delivery networks, testing frameworks, middleware to support security, and more. The more flexibility that you allow for mixing and matching these components, the easier the system is to maintain and improve in the medium and long term.

The technologies that I selected for this article reflect my database management specialization. Apache and Bootstrap are just tools that help me get the application off the ground rapidly. I expect to collaborate with other specialists after the basics are in place. A middleware developer might prefer to continue with a web server framework such as Django or Ruby on Rails, or even a content-management system such as WordPress — so I use Apache in such a way that it can be replaced without greatly affecting the other layers. A web designer would most likely prefer a hand-crafted design rather than Bootstrap, so I use Bootstrap in such a way that it is easily replaceable. Thanks to modern tools and frameworks, it is not a great deal more complicated to prototype web applications in this way, rather than relying on a single, monolithic stack.

Getting started

Filling up the page's containers

The prototype page uses jQuery to load documents from CouchDB into the target divs. I use jQuery's Ajax features directly rather than the jQuery plugin available through CouchDB and CouchApp. The plugin is convenient, but it relies on a tight coupling between CouchDB and the website, with the site's pages as database attachments. I prefer to decouple these, especially during development. Among other things, this allows you to substitute another back end if need be. The JavaScript I use to load the page is straightforward; it is included in this article's code download as poquotes.js.

I will present a simple web application demo: a site for poetry quotes. For help with the installation of CouchDB, see Resources. Once you have CouchDB running on a server, download either the plain Twitter Bootstrap, which is just a bundle of CSS and JavaScript, or the full project bundle. I am working with the full bundle in this article.

I started with the fluid.html example from the Twitter Bootstrap bundle. I trimmed the file, fixed CSS and JavaScript scripts to remove the leading ../assets/, and updated some of the static content for the example site. The result, which I saved as index.html, is in the code bundle for this article (see Download). A significant portion of the HTML page header is in Listing 1:

Listing 1. Part of the index.html page header
<!-- Styles -->
<link href="css/bootstrap.css" rel="stylesheet">
<style type="text/css">
  body {
    padding-top: 60px;
    padding-bottom: 40px;
  }
  .sidebar-nav {
    padding: 9px 0;
  }
</style>
<link href="css/bootstrap-responsive.css" rel="stylesheet">

<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
  <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>

Listing 2 is part of the index.html table into which featured quotations are loaded from CouchDB:

Listing 2. Part of the index.html table into which featured quotes are loaded
<div class="row-fluid">
  <div class="span4 featured-quote">
    <h2>Poet's name</h2>
    <p>Body of quote here.</p>
    <p><a class="btn" href="#">View details &raquo;</a></p>
  </div><!--/span-->
  <div class="span4 featured-quote">
    <h2>Poet's name</h2>
    <p>Body of quote here.</p>
    <p><a class="btn" href="#">View details &raquo;</a></p>
  </div><!--/span-->
  <div class="span4 featured-quote">
    <h2>Poet's name</h2>
    <p>Body of quote here.</p>
    <p><a class="btn" href="#">View details &raquo;</a></p>
  </div><!--/span-->
</div><!--/row-->

This page also includes a mechanism for interacting with the database. In particular, the sidebar includes a form that the user can use to create new quote records. The user accesses the form by clicking a link, which triggers jQuery to make the form appear. Listing 3 shows the form markup. (The first two <input> lines are split to fit this article's page-width limitations.)

Listing 3. The form from index.html for creating a new quote record
<a href="#popup" id="popup">Click to create a new quote</a>
<div>
  <form id="newquote" action="index.html">
    <fieldset>
      <legend>The quote</legend>
      <label for="author">Author's Name</label>
      <input id="author" name="author" type="text" placeholder="First and last name" 
          required="required" autofocus="autofocus">
      <label for="text">Text of the quotation</label>
      <input id="text" name="text" type="textarea" placeholder="Text of the quote here" 
          required="required">
    </fieldset>
    <fieldset>
      <legend>The work</legend>
      <label for="title">Title of the work</label>
      <input id="title" name="title" type="text" required="required">
      <label for="link">Link to the work</label>
      <input id="link" name="link" type="text" required="required">
      <label for="year">Year of the work</label>
      <input id="year" name="year" type="text" required="required">
    </fieldset>
    <input id="donewquote" type="submit" value="Add quote" />
  </form>
</div>

Listing 4 is the section near the end of the index.html page body that loads the necessary JavaScript. The last script line has the specific code for working with the poquotes database in CouchDB.

Listing 4. Loading JavaScript near the end of the index.html page body
<!-- Placed at the end of the document so the pages load faster -->
  <script src="js/jquery-1.7.1.js"></script>
  <script src="js/bootstrap.js"></script>

  <script src="js/poquotes.js"></script>

</body>

In less than 5 minutes, Bootstrap made it possible for me to enjoy the basic setup of a website that offers the most modern features, including graceful support in older browsers and on mobile devices. For your own website, update the colors, fonts, images, and other details to suit your design. You can visit the Bootstrap gallery for plenty of inspiration (see Resources).


Preparing the data

In Listing 2, notice the div elements of the featured-quote class. I will load the data from CouchDB into those elements. The main page features six prominent quotes that are loaded dynamically by the page script and replace the current boilerplate.

Go to Futon, the CouchDB browser-based console — for example, at http://localhost:5984/_utils/ — and create a database named poquotes, as in Figure 1:

Figure 1. Setting up the poquotes database from the CouchDB Futon page
Screen capture from the CouchDB Futon page setting up the poquotes database

Listing 5 is a sample document that contains the information for a quote. (The fourth line is split in two to fit this article's page width.)

Listing 5. Sample JSON document for a quote
{
    "type": "quote",
    "author": "Thomas Hardy",
    "text": "And as the smart ship grew<br>In stature, grace, and hue<br>
In shadowy silent distance grew the Iceberg too.",
    "work": {
            "title": "The Convergence Of The Twain",
            "link": "http://www.poetryfoundation.org/poem/176678",
            "year": 1915
    }
}

I loaded this file as q1.json into the new database using cURL:

curl -u user:passwd -X POST http://localhost:5984/poquotes \
 -H 'Content-Type: application/json' -d @q1.json
{"ok":true,"id":"ca42f5a16ca1905978afdeda68c116c2",
"rev":"1-7fe040eb6d322a35a86d2f871b100ff0"}

The response from CouchDB (which starts with {"ok") indicates that the document was added and gives the generated ID and revision of the new document. CouchDB's RESTful nature makes prototyping data sets for the site almost as easy as manipulating the file system. You can also use Futon to add documents, if you prefer. The downloadable sample code for this article includes six such quote documents — enough to fill the grid of the target page.


Preparing the main query

I used Futon to design a view to load the documents needed for the web page. In Futon you can design temporary views, test them, and then save them for actual use. If possible, design your views early in your development cycle while you have only a few documents in the database because temporary views can quickly slow down. Listing 6 is the view JavaScript:

Listing 6. CouchDB view used to get all quote documents, indexed by year of source work
function(doc) {
  if (doc.type == "quote") {
    emit(doc.work.year, doc);
  }
}

The view is simple, but it does the trick, indexing the results by year of the work because that is how I want to sort the records into the page. To add this view to your database, click the View selector and switch to Temporary view. Then, you can paste Listing 6 into the Map Function box. Click Run to see a table listing of six documents. If that works, save the view with the design document name of by_year. It is no longer a temporary view. You can then go back to trusty cURL to exercise the view:

curl "http://localhost:5984/poquotes/_design/poquotes/_view/\
by_year?&descending=true&limit=6"

The GET parameters (&descending=true&limit=6) adjust how the database delivers the query results. In this case only the six most recent documents are returned in descending order, ensuring that the document with the most recent year field comes first.


Cross-domain limitations

One thing that makes loosely coupled, rapid prototyping of multitiered web applications tricky is the set of cross-domain request restrictions in browsers. For security reasons, browser scripts are severely limited from making HTTP requests except to the same port on the same host as the source page. Several approaches for dealing with this problem are available. One of them is to use JSONP (JSON with padding; see Resources). Listing 7 is an excerpt from poquotes.js — the part that loads records into the target divs:

Listing 7. JavaScript and jQuery code to load the target page with quotes
...
    root: "http://localhost:5984/",
...
    max_quotes: 6,

    //Invoked when the HTML page is first loaded
    loadPage: function()
    {
        var six_latest = poq.root + "poquotes/_design/poquotes/_view/by_year?&limit="
            + poq.max_quotes + "&descending=true&callback=?";
        $.getJSON(six_latest, poq.handleMainQuotes);
...
    },

    //Invoked with the result of the Ajax call to load quote documents
    handleMainQuotes: function(json)
    {
        //Load up to six records, as available
        quote_count = Math.min(poq.max_quotes, json["total_rows"])
        for (var i=0; i<quote_count; i++) {
            var doc = json["rows"][i]["value"]
            var year = doc["work"]["year"].toString()
            var title = doc["work"]["title"].toString()
            var link = doc["work"]["link"].toString()

            //Create an HTML snippet from the fields of each quote document
            qblock = $("<div class='span4 featured-quote'></div>")
              .append("<h2>" + doc["author"] + "</h2>")
              .append("<p style='font-size: 80%; height: 8em;'>" + doc["text"] + "</p>")
              .append("<p>" + year + "</p>")
              .append("<p><a href='" + link + "'>" + title + "</a></p>")
              .append("<p><a class='btn' href='#'>View details &raquo;</a></p>")
            //jQuery's eq selector to find the target div corresponding to the loop index
            $('div.featured-quote:eq(' + i.toString() + ')').replaceWith(qblock);
        }
    },

In Listing 7, the callback=? is added at the end of the URL for loading documents. This tells jQuery to use JSONP for the Ajax GET query to pull documents from CouchDB, required because the database is running on a different port from the web front end. This workaround is also needed if you query a database on a different host.

To make Ajax requests using methods other than GET is trickier. Listing 8 is an excerpt from poquotes.js — the part that creates a new form and sends it to the database:

Listing 8. JavaScript and jQuery code to turn fields from a form into a record and POST it to CouchDB
...
    dbroot: "db/",
...
    //Invoked when the HTML page is first loaded
    loadPage: function()
    {
...
        $('#donewquote').click(function() {
            var db_link = poq.dbroot + "poquotes";
            var record = {
                "type": "quote",
                "author": $("#author").val(),
                "text": $("#text").val(),
                "work": {
                    "title": $("#title").val(),
                    "link": $("#link").val(),
                    "year": parseInt($("#year").val())
                }
            };
            $.ajax({
                url : db_link,
                data : JSON.stringify(record),
                contentType : "application/json", 
                type : 'POST',
                processData : false,
                dataType : "json",
                success : function(resp) {
                    alert("New document created: " + JSON.stringify(resp));
                }
            });
            return false;
        });
        //Set up the collapsible form for adding new quotes
        $('#popup').click(function(){
            $("#newquote").slideToggle();
        });
        //Start out with the create quote form collapsed
        $("#newquote").slideToggle();
    },

In Listing 8, the POST is made to the same host and port, but to a /db/ URL. I use the standard trick of setting up a reverse proxy from that URL to the CouchDB host and port. More specifically, I use an Apache HTTP Server ProxyPass directive. The details of this technique depend on your setup, but it is useful in setting up a web prototype with strong separation between the browser and server layers.


The look and feel

Figure 2 shows the working sample page when it is first loaded, after the target divs are filled with records from the database:

Figure 2. Browser screen after index.html is loaded from the Apache web server
Screen capture of browser screen after index.html is loaded from Apache

The user can select Click to create a new quote to display the form for adding a new quote, as in Figure 3:

Figure 3. Browser screen from index.html with form shown
Screen capture of browser screen from index.html with form shown

Wrap-up

Throughout the article I've explained why I prefer certain techniques for prototyping web applications. They make it easier for the web design and the middleware to proceed in independent, parallel tracks, which feels like a more natural separation of concerns. I would rather have a dedicated web server hosting the site, even in development, than a DBMS.

In this article, I glossed over details of user authentication and authorization on CouchDB. After the prototyping stage, I update the middleware to handle user management, sessions, and the like. I can forward these concerns to CouchDB's facilities or use separate frameworks, depending on the project. This is the key flexibility that I gain. The web application gains a few details pertaining to logging in and session management, but usually it is an independent layer.

My intention in this article is not to disparage other approaches for prototyping on a NoSQL platform. I offer it as an alternative approach that is worth considering. It can be fun as well as productive to combine the most interesting open source projects, focusing each on its core strengths. In the process, you also learn many important details that too often get glossed over by tools that couple layers together too tightly.


Download

DescriptionNameSize
Sample web application for this articlecouchdb-dw.zip9KB

Resources

Learn

Get products and technologies

Discuss

  • Get involved in the developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Open source
ArticleID=932009
ArticleTitle=Prototype web applications with CouchDB and Bootstrap
publish-date=06042013