Contents


Build a simple word game app using Cloudant on Bluemix

Comments

This article was written using the Bluemix classic interface. Given the rapid evolution of technology, some steps and illustrations may have changed.

IBM Bluemix™ is a new open platform for developing and deploying web and mobile applications. In this article, I'll walk you through the steps to create a simple GuesstheWord game application using Bluemix and its cloud-based development environment: DevOps Services. You will start from scratch and end up with a simple game you can play in a web browser with server code running in the cloud.

When you have completed the steps in this article, you'll be ready to develop your own Bluemix applications of any size.

Although this application is simple, I'll cover aspects that are important when developing larger applications, such as setting up a good development environment to enable local debugging. My goal is to walk you through the development of a small Bluemix application using an approach that is also applicable to development of large Bluemix applications. When you have completed the steps in this article, you'll be ready to develop your own Bluemix applications of any size.

Run the appGet the code

What you will need for your application

To follow along, you'll need a Bluemix account. Also, if this is the first time you've heard about Bluemix, you may want to read this short introduction.

When embarking on a development project, it is important to choose the right technologies. Bluemix supports a multitude of technologies for developing applications. In fact, this flexibility is one of the main strengths of the platform because it allows you to choose which technologies are best suited for the applications you want to develop. For our Guess-the-Word game, we'll use the following:

  • Node.js— For the server-side code, we'll use Node.js. Web servers implemented in Node.js start up quickly and are easy to develop and debug locally. It can also be a benefit to use the same language, such as JavaScript, for both server- and client-side code. We'll also use the Express framework with Node.js because it provides useful functionality when implementing a web server.
  • Cloudant— For persisting server data (the top game scores) we will use a Cloudant database. A NoSQL database like Cloudant is easy to use with JavaScript and JSON encoded data.
  • HTML, CSS, and JavaScript— The UI of the game will be implemented using HTML, CSS, and JavaScript. With the support for HTML5 and CSS3 in modern web browsers, this is a natural choice because it will allow our game to be run on phones and tablets, as well as computers.
  • Bootstrap and JQuery— We will also use the Bootstrap and JQuery JavaScript frameworks, which provide nice functionality for web UI development.
  • Jade— To save us some typing, we'll use a template language for our HTML pages. There are several template languages available for Node.js. I decided on Jade because it is often used with the Express framework.

With these decisions made, we're ready to start coding.

Step 1. Write the server code

  1. Let's start by implementing the core part of the Node.js server so we can test it before implementing the UI. We could use Eclipse for the coding, but at the time of this writing, support for Node.js in Eclipse is still somewhat basic, especially when it comes to debugging. So we'll use a utility called node-inspector for debugging our Node.js server code. Feel free to use your favorite text editor for the code below:
    /**
     * Server for the GuessTheWord app
     */
    
    var express = require('express');
    var app = express();
    var http = require('http');
    
    var host = "localhost";
    var port = 3030;
    
    // Set path to Jade template directory
    app.set('views', __dirname + '/views');
    
    // Set path to JavaScript files
    app.set('js', __dirname + '/js');
    
    // Set path to CSS files
    app.set('css', __dirname + '/css');
    
    // Set path to image files
    app.set('images', __dirname + '/images');
    
    // Set path to sound files
    app.set('sounds', __dirname + '/sounds');
    
    // Set path to static files
    app.use(express.static(__dirname + '/public'));
    
    // Bind the root '/' URL to the hiscore page
    app.get('/', function(req, res){
      res.render('hiscores.jade', {title: 'Hiscores'});
    });
    
    // Bind the '/play' URL to the main game page
    app.get('/play', function(req, res){	
      res.render('main.jade', {title: 'Guess the Word'});
    });
    
    var server = app.listen(port, function() {
      console.log('Server running on port %d on host %s', server.address().port, host);
    });
    
    process.on('exit', function() {
      console.log('Server is shutting down!');
    });
  2. Save this code in a file called server.js, then create a folder called views to contain the two Jade files (hiscores.jade and main.jade), referenced in the code above and shown below. These Jade files define the contents of the two web pages used by the game.
  3. The hiscores.jade file shows the high scores. This is the initial page of the game and is bound to the root URL '/'.
    doctype html
    html(lang="en")
      head
        title= title
        link(rel="stylesheet", href="css/bootstrap.css", type="text/css")
        link(rel="stylesheet", href="css/hiscores.css", type="text/css")
      body(style="background-image:url(/images/background.jpg)")
    
        div(class="container")
          h1(id="header") High Scores
          table(id="hiscore_table")
            tr()
              th(class="table-header") Score
              th(class="table-header") Name
              th(class="table-header") Date
          div(style="padding-top:30px;")
            a(class="btn btn-default", href="/play") Play!
          
        script(src="js/jquery.js", type="text/javascript")
        script(src="js/bootstrap.js", type="text/javascript")
        script(src="js/hiscores.js", type="text/javascript")
  4. The main.jade file is the page where the game is played. It is bound to the URL '/play'.
    doctype html
    html(lang="en")
      head
        title= title
        link(rel="stylesheet", href="css/bootstrap.css", type="text/css")
        link(rel="stylesheet", href="css/main.css", type="text/css")
      body(style="background-image:url(/images/background.jpg)")
    
        div(class="container")
          h1(class="game-text") Guess the secret word!
          div(class="row")
            div(class="col-xs-8")
              div(id="word-description")        
            div(class="col-xs-4")
               div(id="score") Score:        
               
          div(class="row")
            div(class="col-xs-8")
              div(class="word-area")
                table()
                  tr()        
            div(class="col-xs-4")
              div(id="power") Power:            
          div(class="row")
            div(class="col-xs-8")
              div(id="help-text", class="game-text") Click on a ?-box above and type a letter          
            div(class="col-xs-4")
              div(class="row")
                div(class="col-xs-12")
                  button(id="skip-button" class="btn btn-info btn-xs") Skip this word
                div(class="col-xs-12")
                  button(id="help-letter-button" class="btn btn-info btn-xs") Give me a letter
              
        
        audio(id="tick-sound", src="sounds/Tick.mp3")
        audio(id="skip-sound", src="sounds/Falcon.mp3")
        audio(id="applause-sound", src="sounds/Applause.mp3")
          
        script(src="js/jquery.js", type="text/javascript")
        script(src="js/bootstrap.js", type="text/javascript")
        script(src="js/main.js", type="text/javascript")

As you can see, these Jade files reference a lot of static files, such as CSS and JavaScript files. We'll add those later, but first, let's run a test of what we have so far.

Step 2. Run and debug the server code

  1. If you haven't already installed Node.js locally, now is the time. Download from Nodejs.org and follow the instructions. We install Node.js locally so we can run and debug the server code locally before deploying it to Bluemix.
  2. You also need to install the Express and Jade modules for Node.js. The easiest way to do this is to first create a package.json file in the root folder that specifies the dependencies to these libraries.
    {
    	"name": "GuessTheWord",
    	"version": "0.0.1",
    	"description": "GuessTheWord package.json file",
    	"dependencies": {
    		"express": ">=3.4.7 <4",
    		"jade": ">=1.1.4"
    	},
    	"engines": {
    		"node": ">=0.10.0"
    	},
    	"repository": {}
    }

    Now you can install Express and Jade by opening a command-line prompt in the root folder and entering the following command:

    > npm install

    By the time you read this, there may be versions of Express and Jade available that are newer than the versions shown above. You may of course use these versions instead. As long as all dependencies of the application are mentioned in package.json, the same versions of the libraries will be used when you develop locally and when you later deploy to Bluemix. This is good because you avoid surprises caused by different library versions being used in the different environments.

  3. Make a first run of your application with the following command:
    > node --debug server.js
  4. Open a web browser and go to http://localhost:3030/. Image shows http://localhost:3030
  5. Before we proceed with game development, let's make sure we can debug the application. First, we install node-inspector. Open a new command line and type the following command:
    > npm install -g node-inspector
  6. Because we launched the application with the --debug flag, we can now start node-inspector like this:
    > node-debug server.js

    This opens a JavaScript debugger in your default web browser, which should be either Chrome or Opera. If you have another web browser as default, you can instead use the following command:

    > node-inspector

    Open http://127.0.0.1:8080/debug?port=5858 in Chrome or Opera to start debugging. If you have not used this debugger before, you may want to read this introduction.

Step 3. Implement the client code

  1. Now let's create the missing files referenced by the Jade files. All binary files (JPG and MP3) can be downloaded from the completed GuessTheWord DevOps Services project, which contains all files referenced in this article. The easiest way to download them is to go to the EDIT CODE tab, right-click on the containing folder and Export the contents as a zip file for download. Image shows                             creating the missing files
    Image shows creating the missing files

    You can of course also choose to create your own images and sounds to give a more personal touch to the game.

  2. The following files constitute the JQuery and Bootstrap JavaScript libraries. They can also be downloaded from the GuessTheWord DevOps Services project, or from the Internet.
    1. Download to folder public/js:
      • jquery.js (the latest version of the JQuery JavaScript library)
      • bootstrap.js (the latest version of the Bootstrap JavaScript library)
    2. Download to folder public/css:
  3. Now create the following two CSS files, which define the styles used in the game:
  4. Run the application again locally to see these changes take effect. Go to the root folder of the application (making sure it's the folder the local Git repository is connected to), then run:
    > node-debug server.js

    The game should now look a bit nicer than before:

    Image shows                             game creation progress
  5. Next, let's write the client-side JavaScript that implements the game logic. We'll wait a bit before implementing hiscores.js since populating the high-score list requires a database, something we will add later. Instead, create the file public/js/main.js with the contents found in this code snippet, which basically contains all the game logic. It takes care of getting a random English word with a description from the server, handling keyboard input by the player, counting score, managing power, etc.

    As you can see, the function getNewSecretWord() invokes a /randomword service on the web server in order to get the secret word.

  6. Let's implement this service by adding the following code to server.js (after the initial variable declarations).
    /**
     * Lookup the word in the wordnik online dictionary and return a description for it.
     * @param word {String} Word to lookup description for
     * @param cb_description {function} Callback with the description as argument. 
     * If the word was not found in the dictionary the description is empty.
     */
    function wordLookup(word, cb_description) {
      http.request(
        {
          host: "api.wordnik.com",
          path: "/v4/word.json/" + word +
            "/definitions?limit=1&api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5"
        },	function (res) {
          var str = '';
          res.on('data', function(d) {
            str += d;
          });
          res.on('end', function() {
          var wordList = JSON.parse(str);
          cb_description(wordList.length > 0 ? wordList[0].text : "");
        });
      }).end();	
    }
    
    app.get('/randomword', function(request, response) {
      http.request(
        {
          host: "api.wordnik.com",
          path: "/v4/words.json/randomWord?hasDictionaryDef=false&minCorpusCount=0&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=5&maxLength=-1&api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5"
        }, function (res) {
          var str = '';
          res.on('data', function(d) {
            str += d;
          });
          res.on('end', function() {
            var wordObj = JSON.parse(str);
            wordLookup(wordObj.word, function(descr) {
            var randomWordObj = { word : wordObj.word, description : descr };
            response.send(JSON.stringify(randomWordObj));		
          });								
        });
      }).end();
    });

    This code binds the /randomword URL to code that uses Wordnik.com, an online English dictionary, to get a random word. It then calls wordLookup(), which makes another call to the Wordnik API in order to get the description of that word. Finally, the secret word and its description are encoded as JSON and returned as the response of the HTTP request.

    Note: The API key included in the above code snippet is for a free account shared by many people, so it can only be used on a small scale. To avoid this restriction, you can register at Wordnik and get your own API key.

  7. At this point, you may want to run a few debug sessions locally to step through the client- and server-side code to verify that the game works as expected. Image shows                             verifying that the                     game works as expected
    Image shows verifying that the game works as expected

    The client-side JavaScript is debugged using the embedded Chrome debugger. The server-side JavaScript is debugged using node-inspector as described earlier. Note that node-inspector uses the same Chrome debugger for server-side Node.js JavaScript debugging.

Step 4. Create a DevOps Services project

Now that we have a working application we can run and debug locally, our next step is to store what we've written so far in a DevOps Services repository. This provides a number of benefits, including:

  • The code is stored in the cloud, which is more secure than a local computer.
  • Other people can contribute to the development of the application.
  • We can enable automatic deployment to Bluemix.
  1. Sign in at DevOps Services and click Start coding to create a project for our application. The choice between Jazz SCM and Git SCM is arbitrary and will typically depend on which SCM system you are most familiar with. We'll choose a Git repository for our project, and mark the Deploy to Bluemix checkbox since we'll be deploying our app to Bluemix. Select a Bluemix organization and space, then click CREATE. Image shows creating the project
    Image shows creating the project
  2. Your new project will initially be empty, except for a couple default files. To add your code to the project, click EDIT CODE, then drag/drop the files from your file system into the file hierarchy of the project (the tree shown to the left).

    If you wrote the code using Eclipse, you can drag/drop the files directly from Eclipse Project Explorer. Note that you then should select the individual files and folders under the Eclipse project (not the project itself) and drag/drop them onto the top node (marked in red) in the project file hierarchy. Also note that Eclipse hides some files, for example the .project file, so you still may have to drag/drop some files from your file system.

    Your project file hierarchy should now show all the files of your application.

    Note that even though you just copied the files from your local computer into a DevOps Services project, the changes you made are still not committed and pushed to the Git repository. This means that no one else can see the files you added. Think of the file hierarchy shown under your DevOps Services project as your personal work area, much like your local file system except it's stored in the cloud.

  3. If you click on the repository icon, you'll see a number of uncommitted changes, one for each file you added. The files are shown as "Unstaged," which is Git terminology for a change that has not yet been committed to the repository. Image shows repository icon
  4. To commit the changes, perform the Stage the change command on each file: Image shows stage button

    This moves the files from Unstaged to Staged. All changes shown under Staged will be committed as a single change set when you click COMMIT. In this case, we want to add all files in a single change set, but you may later want to commit some changes as one change set and other changes as another change set. Each change set should group changes that logically belong together.

    Your Commit message in the Commit dialog should describe the change set, and perhaps provide a reason for the change.

    Image shows                             commit
    Image shows commit
  5. When you click SUBMIT, the change set is committed to Git and appears as a single change set under the Commits section. Image shows committed changes, not yet pushed
    Image shows committed changes, not yet pushed
  6. The final step is to push this change set to the master branch so others can fetch it from there. Click PUSH, then click OK to push your changes. Image shows pushed changes
  7. At this point, your local copy of the code is redundant and you should consider deleting it. If you continue to develop on your local copy, remember to upload all modified files to your DevOps Services project and deliver the changes in the same way you just did. It is possible to work in this way, but it may be confusing and a bit cumbersome.

    A more practical approach is to either abandon local development altogether and edit the code using the web editor in DevOps Services, or to set up a local Git repository connected to the DevOps Services Git repository. I chose the second alternative because we want to be able to develop and debug locally, something which is not yet possible using the DevOps Services web editor.

    There are a couple of ways to set up a local Git repository connected to the DevOps Services Git repository. If you use an IDE such as Eclipse or Visual Studio, you can use the Git plugin for these IDEs to import the DevOps Services Git repository into the IDE. If you develop in an environment where no Git plugin is available, you can use Git from the command line. In either case, you need the URL for the DevOps Services Git repository. You can get this URL from the overview page of your DevOps Services project.

    To get to the project overview page from the EDIT CODE tab, click the project link in the top-left corner.

    Image shows project overview page

    Then click on the Git URL link:

    Image shows Git URL
    Image shows Git URL
  8. Once you have cloned this URL into a local Git repository, you can continue to develop the application locally and commit changes directly to the DevOps Services Git repository without going through the DevOps Services web interface. If you use Eclipse and the EGit plugin, your project view will look something like the screenshot below. If your Eclipse doesn't already contain the EGit plugin, it's easy to install. If you are new to EGit, consult the User Guide.Image shows an Eclipse project showing the files of the application stored in a Git repository
    Image shows an Eclipse project showing the files of the application stored in a Git repository

Step 5. Deploy your application to Bluemix

At this point, it's a good idea to make a first deployment to Bluemix, just to make sure we have this working before we continue developing the game.

  1. Deployment is controlled by a file called manifest.yml, so we need to create this file in the root folder of our application.
    ---
    applications:
    - name: GuessTheWord
      framework: node
      runtime: node08
      memory: 64M
      instances: 1
      host: GuessTheWord
      path: .     
      command: node server.js

    These settings tell Bluemix how to deploy our application. For example, we specify the runtime (Node.js), the amount of memory to reserve for our application, and the host name we wish to use in the URL of our deployed application. Note that the host name must be globally unique, so you'll need to pick a host name other than "GuessTheWord."

  2. Whether you create this file in the DevOps Services web editor or in your local development environment, don't forget to push the new file to the DevOps Services Git repository.
  3. To start a deployment, click the BUILD & DEPLOY button on your DevOps Services project. Image shows the Build & Deploy tab
    Image shows the Build & Deploy tab

    Then toggle the switch at the top of the page from OFF to SIMPLE to deploy to Bluemix.

    Image shows auto-deploy buttons
  4. As soon as you do this, DevOps Services attempts to deploy your application to Bluemix. Image shows simple auto-deploy enabled
    Image shows simple auto-deploy enabled

    Also, a new deployment will take place automatically whenever someone pushes changes to the DevOps Services Git repository. This is convenient because it allows us to always have access to the latest deployed version of the application to run tests, for example.

  5. After 30 seconds or so, you should see that the application deployed without errors. Image shows auto-deploy message
    Image shows auto-deploy message
  6. To access the deployed application in Bluemix, click the link above the list. Image shows link to deployed application
    Image shows link to deployed application

Step 6. Troubleshoot Bluemix deployment

When you attempt to access your deployed application you will probably see the following message:

404 Not Found: Requested route ('guesstheword.mybluemix.net') does not exist.

This doesn't look good. There is obviously a problem somewhere, and it seems related to the application running on Bluemix since it ran fine locally.

This illustrates an important point: An application may be successfully deployed but still not be available when you try to access it. The green status indicator and an OK result in the Recent Auto-Deployments list just means that the application was successfully deployed and started. However, it may, for example, terminate shortly after starting and not be available when you try to access its Bluemix URL.

To troubleshoot these kinds of problems, it would be nice to be able to debug your server code on Bluemix. This likely will be possible in the future, but Bluemix does not yet support this. What you can do, however:

  1. Look at log files within DevOps Services to find out what went wrong. Also, you can sometimes get additional information by using the Bluemix cf CLI tool. For example:
    > cf app GuessTheWord
    Showing health and status for app GuessTheWord in org mattias.mohlin@se.ibm.com
    / space dev as mattias.mohlin@se.ibm.com...
    OK
    
    requested state: started
    instances: 0/1
    usage: 64M x 1 instances
    urls: GuessTheWord.mybluemix.net
    
         state      since                    cpu    memory   disk
    #0   crashing   2014-04-24 01:10:37 PM   0.0%   0 of 0   0 of 0

    Here we see that the state of the application is crashing, which means it somehow terminated. A web server should never terminate so we need to find out why ours terminates when running on Bluemix.

  2. In DevOps Services on the EDIT CODE tab, there's a DEPLOY button, but don't click it yet. Image shows the Deploy button

    This button is for manual deployment of the contents of your personal DevOps Services project area to Bluemix. This is useful when troubleshooting because it lets you add temporary logging or other experiments you don't want to commit to the master branch. Before we click DEPLOY, we need to fetch all incoming change sets to bring our DevOps Services project area up-to-date with the master branch.

  3. Go to the Git Status page and click the FETCH button. Incoming change sets are shown under the Commits section. Click the MERGE button to merge these incoming change sets into your DevOps Services project area.
  4. Now we can do a manual deployment by clicking the DEPLOY button. When the application has deployed to Bluemix, you will see this: Image shows that manual deployment is ready
    Image shows that manual deployment is ready
  5. Click the root folder page link in the above message to view manual deployment information. Image shows that app deployed on Bluemix is not running
    Image shows that app deployed on Bluemix is not running

    We see a red indicator, confirming that the application is not running. Click the Logs link to view logs produced by the application before it terminated.

    Image shows                             log files
  6. Open the stdout.log file. Image shows contents of the file stdout.log
    Image shows contents of the file stdout.log

    From this log, you probably immediately understand what's wrong. Our web server tries to use a hard-coded host name (localhost) and port number (3030). This works fine when running the server locally, but not on Bluemix.

  7. The solution is to add the following piece of code just after the declaration of the host and port variables in the server.js file:
    if (process.env.hasOwnProperty("VCAP_SERVICES")) {
      // Running on Bluemix. Parse out the port and host that we've been assigned.
      var env = JSON.parse(process.env.VCAP_SERVICES);
      var host = process.env.VCAP_APP_HOST;
      var port = process.env.VCAP_APP_PORT;	
    }

    Bluemix uses an environment variable called VCAP_SERVICES for passing information about the environment to the server. The host and port are examples of such information. Note that the above if statement will not be executed when we run the server locally because VCAP_SERVICES is not set then. Therefore, we can run and debug our application locally even after this change.

  8. Let's push this change to the Git repository and let auto-deploy do its job. We see the deployment was successful. Image shows auto-deploy of changes to not use a hardcoded host and port
    Image shows auto-deploy of changes to not use a hardcoded host and port
  9. If we now click the link to the deployed application, we have reason for a small celebration. Image shows GuessTheWord game running on Bluemix
    Image shows GuessTheWord game running on Bluemix

    Voilà! Our game is running on Bluemix.

  10. Now take a well-deserved break and play the game. See how many words you can guess before running out of power.

Step 7. Add a database service

Did you achieve a great score? Congratulations! Too bad it's not saved so that others can see how good you are at word guessing. Let's fix this by persisting the scores in a database. You may think a database is overkill for saving so little data. Couldn't we just keep the high-score list in a text file on the server? Yes, but it's not a good idea because a Bluemix server may not always run on the same physical machine (due to load balancing). Therefore, it is not recommended to persist data using files, but instead to use some kind of cloud service for persistence.

There are a number of cloud storage solutions to choose from, but let's keep it simple. Let's add a Cloudant database service to our application:

  1. Go to the Bluemix web app by clicking the MANAGE button in the BUILD & DEPLOY tab. Image shows the Manage button
    Image shows the Manage button
  2. This takes us to the GuessTheWord app in Bluemix. We can see that our application is running, but there are no services associated with it. Click Add a service to add a new service. In the Data Management section of the Bluemix catalog, choose Cloudant NoSQL DB. Image shows Cloudant icon in Bluemix
  3. Click on the service, then on Create in the dialog. The application will restart, which should only take a few seconds. Then click Show Credentials on the added service: Image shows dialog for adding the Cloudant database service
    Image shows dialog for adding the Cloudant database service

A Cloudant account is automatically created with the generated username and password. Copy the value of the URL field since you will need it when writing the code for accessing the database below.

Step 8. Use the Cloudant database

  1. Click on the service, then Launch. This takes you to the Cloudant web UI where you can configure and administer the database. Image shows Launch button
  2. Create a new database named guess_the_word_hiscores. Then click the button to create a new secondary index. Store it in a document named top_scores and name the index top_scores_index. Image shows creating secondary index in Cloudant DB
    Image shows creating secondary index in Cloudant DB
  3. The map function defines which objects in the database are categorized by the index and what information we want to retrieve for those objects. We use the score as the index key (the first argument to emit), then emit an object containing the score, the name of the player, and the date the score was achieved. Following is the JavaScript implementation of the map function, which you can copy/paste.
    function(doc) {
     emit(doc.score, {score : doc.score, name : doc.name, date : doc.date});
    }
  4. Let's write the code necessary for storing scores in the Cloudant database. We'll use the DevOps Services web editor this time. You'll need to decide which Node.js library to use for accessing Cloudant. I chose the nano library.

    Click on the package.json file in the DevOps Services file hierarchy, then add the line "nano" : "*", as shown below. This will include the latest version of the nano library in your application.

    	"dependencies": {
    		"express": ">=3.4.7 <4",
    		"jade": ">=1.1.4",
    		"nano" : "*"
    	},

    As with the host and port, Bluemix uses the VCAP_SERVICES environment variable to tell our application about the Cloudant database service (where it's running, which credentials to use for logging into it, etc.). Add the lines marked in italics below to the server.js file. Replace the URL string with the value you copied from the service credentials previously.

    var express = require('express');
    var app = express();
    var http = require('http');
    
    var host = "localhost";
    var port = 3030;
    var cloudant = {
    		 		 url : "<url>" // TODO: Update		 		 
    };
    if (process.env.hasOwnProperty("VCAP_SERVICES")) {
      // Running on Bluemix. Parse out the port and host that we've been assigned.
      var env = JSON.parse(process.env.VCAP_SERVICES);
      var host = process.env.VCAP_APP_HOST;
      var port = process.env.VCAP_APP_PORT;
    
      // Also parse out Cloudant settings.
      cloudant = env['cloudantNoSQLDB'][0].credentials;  
    }
    var nano = require('nano')(cloudant.url);
    var db = nano.db.use('guess_the_word_hiscores');

    As you can see, the above code will also work when the application does not run on Bluemix. When running locally, the application can use the Cloudant database just as when running on Bluemix.

  5. Now let's handle two new URLs in our server:
    • /hiscores (for getting the top high scores from the database)
    • /save_score (for saving a new high score to the database)

    The code is shown below:

    app.get('/hiscores', function(request, response) {
      db.view('top_scores', 'top_scores_index', function(err, body) {
      if (!err) {
        var scores = [];
          body.rows.forEach(function(doc) {
            scores.push(doc.value);		      
          });
          response.send(JSON.stringify(scores));
        }
      });
    });
    
    app.get('/save_score', function(request, response) {
      var name = request.query.name;
      var score = request.query.score;
    
      var scoreRecord = { 'name': name, 'score' : parseInt(score), 'date': new Date() };
      db.insert(scoreRecord, function(err, body, header) {
        if (!err) {       
          response.send('Successfully added one score to the DB');
        }
      });
    });
  6. We don't have any calls to these new URLs yet, but we can still test the database connection by invoking the above URLs directly from a browser.

    Click on Git Status, push all changes to the DevOps Services Git repository, and wait for the application to be deployed to Bluemix. Then enter the following in a browser, replacing guesstheword in the URL with the host name you chose for your application.

    http://guesstheword.mybluemix.net/save_score?name=Bob&score=4

    You should see a success message. Enter the following URL, again replacing guesstheword with your application host name.

    http://guesstheword.mybluemix.net/hiscores

    The entry you just added should appear encoded in JSON.

    [{"score":4,"name":"Bob","date":"2014-05-07T12:12:31.093Z"}]

    This shows that our code for using the database is working correctly.

  7. Now let's create the missing JavaScript file for populating the score table on the main page of our game. In the web editor, right-click on the folder public/js and select New > File. Image shows creating a file in the web editor

    Name the file hiscores.js and give it the following contents.

    /**
     * Hiscores
     */
    
    function createTableRow(name, score, date) {
      var dateObj = new Date(date);
      var formattedDate = dateObj.toLocaleDateString() + " " + dateObj.toLocaleTimeString();
      return '<tr> <td>' + score + '</td><td>' + name + '</td><td>' + formattedDate + '</td></tr>';
    }
    
    /**
     * Populate the hiscore table by retrieving top 10 scores from the DB. 
     * Called when the DOM is fully loaded.
     */
    function populateTable() {	
      var table = $("#hiscore_table tr");
      $.get("/hiscores", function (data) {
        var hiscores = JSON.parse(data);
        hiscores.forEach(function (hiscore) {
          var html = createTableRow(hiscore.name, hiscore.score, hiscore.date);
          table.last().after(html);		
        });
      });	
    }
    
    $(populateTable);

    This code populates the table with the top scores retrieved from the database. Push the changes to the DevOps Services Git repository and wait until the application gets redeployed on Bluemix. Now when we access the application, we should see the fake score entry that we previously added to the database:

    Image shows high-score table
    Image shows high-score table
  8. We have just a few final things to fix so the score is saved when the game is over. In the main.js file, locate the following line:
    // TODO: Save name and score in DB

    And replace it with:

    saveScore(name, score);

    Add the saveScore() function:

    function saveScore(name, score) {
      $.ajax({url: "/save_score?name=" + name + "&score=" + score, cache : false}).done(function(data) {
        window.location.replace("/"); // Go to hiscore page
      });
    }
  9. Finally, create a Bootstrap "Game Over" dialog by adding the following as the first div in the file main.jade:
    div(id="name-dialog", class="modal fade")
      div(class="modal-dialog")
        div(class="modal-content")
          div(class="modal-header")
            h4(class="modal-title")
          div(class="modal-body")
            div(class="divDialogElements")
              label(for="name-input", style="display:table-cell; width:100%") Enter your name:
              input(class="xlarge", id="name-input", name="xlInput", type="text", style="display:table-cell; width:100%")            				
          div(class="modal-footer")
            button(type="button", class="btn btn-ok") OK
  10. Push the changes, wait for auto-deployment, then play the game once to confirm that your score is saved in the database and appears in the table on the main page. Image shows the final game
    Image shows the final game

Conclusion

In this article, you have built a GuesstheWord game using IBM DevOps Services and deployed the app on Bluemix. You have seen how the code can be developed in the web editor, or in Eclipse (or another IDE), then pushed to the IBM DevOps Services Git repository. You have also seen how to set up automatic deployment so the application is redeployed as soon as new changes are pushed. You have also learned how to debug your application locally, and how to troubleshoot problems that may occur when the application runs on Bluemix. You are now ready to develop your own Bluemix applications.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Cloud computing
ArticleID=977280
ArticleTitle=Build a simple word game app using Cloudant on Bluemix
publish-date=09032014