Adding JavaScript

In this part of the tutorial, you'll create the JavaScript to support the UI in the index.html page that makes a simple GET request to the backend API. The JavaScript will perform two basic functions:

  • Load the backend API interface.
  • Send the Get Greeting request to the backend when the user clicks Submit and display the results.

Adding JavaScript in base.js

To add the JavaScript:

Create the subdirectory static/js in the main backend API project directory helloendpoints.
  1. In the js subdirectory, add a file named base.js. There is nothing magic about the subdirectory and file name; in your own code you can use whatever you want. Our tutorial expects /js/base.js.

  2. In base.js, add the following lines to set namespaces expected for this sample:

    /**
     * @fileoverview
     * Provides methods for the Hello Endpoints sample UI and interaction with the
     * Hello Endpoints API.
     */
    
    /** google global namespace for Google projects. */
    var google = google || {};
    
    /** appengine namespace for Google Developer Relations projects. */
    google.appengine = google.appengine || {};
    
    /** samples namespace for App Engine sample code. */
    google.appengine.samples = google.appengine.samples || {};
    
    /** hello namespace for this sample. */
    google.appengine.samples.hello = google.appengine.samples.hello || {};
    
  3. In base.js, append the following lines to load the backend API interface and perform some initialization upon page load:

    /**
     * Initializes the application.
     * @param {string} apiRoot Root of the API's path.
     */
    google.appengine.samples.hello.init = function(apiRoot) {
      // Loads the OAuth and helloworld APIs asynchronously, and triggers login
      // when they have completed.
      var apisToLoad;
      var callback = function() {
        if (--apisToLoad == 0) {
          google.appengine.samples.hello.enableButtons();
        }
      }
    
      apisToLoad = 1; // must match number of calls to gapi.client.load()
      gapi.client.load('helloworld', 'v1', callback, apiRoot);
    };
    

    In the above code, the hello.init function gets passed the backend API's URL (apiRoot) from the index.html when that page is loaded, through the init function defined in index.html. We specify the API version we want to load, and provide a callback function to execute after the API is loaded. In our callback, we turn on the buttons, which are disabled otherwise.

    Notice that the callback is executed only after all the APIs are loaded in the calls to gapi.client.load. If you wish to use multiple Endpoints APIs or other Google APIs in your JavaScript, increment apisToLoad once for each API and add an additional call to gapi.client.load for each API you want to use.

  4. In base.js, append the following lines that enable the buttons for the above callback when the backend API loads successsfully:

    /**
     * Enables the button callbacks in the UI.
     */
    google.appengine.samples.hello.enableButtons = function() {
      var getGreeting = document.querySelector('#getGreeting');
      getGreeting.addEventListener('click', function(e) {
        google.appengine.samples.hello.getGreeting(
            document.querySelector('#id').value);
      });
    
      var listGreeting = document.querySelector('#listGreeting');
      listGreeting.addEventListener('click',
          google.appengine.samples.hello.listGreeting);
    
    };
    
  5. In base.js, append the following code:

    
    /**
     * Prints a greeting to the greeting log.
     * param {Object} greeting Greeting to print.
     */
    google.appengine.samples.hello.print = function(greeting) {
      var element = document.createElement('div');
      element.classList.add('row');
      element.innerHTML = greeting.message;
      document.querySelector('#outputLog').appendChild(element);
    };
    
    /**
     * Gets a numbered greeting via the API.
     * @param {string} id ID of the greeting.
     */
    google.appengine.samples.hello.getGreeting = function(id) {
      gapi.client.helloworld.greetings.getGreeting({'id': id}).execute(
          function(resp) {
            if (!resp.code) {
              google.appengine.samples.hello.print(resp);
            }
          });
    };
    
    /**
     * Lists greetings via the API.
     */
    google.appengine.samples.hello.listGreeting = function() {
      gapi.client.helloworld.greetings.listGreeting().execute(
          function(resp) {
            if (!resp.code) {
              resp.items = resp.items || [];
              for (var i = 0; i < resp.items.length; i++) {
                google.appengine.samples.hello.print(resp.items[i]);
              }
            }
          });
    };
    

    This code handles the user's Submit button clicks and displays the results in the browser. The List Greetings button gets all the greetings, and the Get Greeting button gets the greeting specified in the form.

    Notice how the getGreeting function in base.js invokes the backend API to send the ID parameter in the GET request:

    gapi.client.helloWorld.greetings.getGreeting({'id': id})
    
  6. When you are finished, your file should look like this:

    /**
     * @fileoverview
     * Provides methods for the Hello Endpoints sample UI and interaction with the
     * Hello Endpoints API.
     */
    
    /** google global namespace for Google projects. */
    var google = google || {};
    
    /** appengine namespace for Google Developer Relations projects. */
    google.appengine = google.appengine || {};
    
    /** samples namespace for App Engine sample code. */
    google.appengine.samples = google.appengine.samples || {};
    
    /** hello namespace for this sample. */
    google.appengine.samples.hello = google.appengine.samples.hello || {};
    
    /**
     * Prints a greeting to the greeting log.
     * param {Object} greeting Greeting to print.
     */
    google.appengine.samples.hello.print = function(greeting) {
      var element = document.createElement('div');
      element.classList.add('row');
      element.innerHTML = greeting.message;
      document.querySelector('#outputLog').appendChild(element);
    };
    
    /**
     * Gets a numbered greeting via the API.
     * @param {string} id ID of the greeting.
     */
    google.appengine.samples.hello.getGreeting = function(id) {
      gapi.client.helloworld.greetings.getGreeting({'id': id}).execute(
          function(resp) {
            if (!resp.code) {
              google.appengine.samples.hello.print(resp);
            }
          });
    };
    
    /**
     * Lists greetings via the API.
     */
    google.appengine.samples.hello.listGreeting = function() {
      gapi.client.helloworld.greetings.listGreeting().execute(
          function(resp) {
            if (!resp.code) {
              resp.items = resp.items || [];
              for (var i = 0; i < resp.items.length; i++) {
                google.appengine.samples.hello.print(resp.items[i]);
              }
            }
          });
    };
    
    /**
     * Enables the button callbacks in the UI.
     */
    google.appengine.samples.hello.enableButtons = function() {
      var getGreeting = document.querySelector('#getGreeting');
      getGreeting.addEventListener('click', function(e) {
        google.appengine.samples.hello.getGreeting(
            document.querySelector('#id').value);
      });
    
      var listGreeting = document.querySelector('#listGreeting');
      listGreeting.addEventListener('click',
          google.appengine.samples.hello.listGreeting);
    
    };
    /**
     * Initializes the application.
     * @param {string} apiRoot Root of the API's path.
     */
    google.appengine.samples.hello.init = function(apiRoot) {
      // Loads the OAuth and helloworld APIs asynchronously, and triggers login
      // when they have completed.
      var apisToLoad;
      var callback = function() {
        if (--apisToLoad == 0) {
          google.appengine.samples.hello.enableButtons();
        }
      }
    
      apisToLoad = 1; // must match number of calls to gapi.client.load()
      gapi.client.load('helloworld', 'v1', callback, apiRoot);
    };
    
  7. In the main backend API project directory helloendpoints, edit the app.yaml file to add handler support for the web app. Add these lines.

    - url: /js
      static_dir: static/js
    - url: /bootstrap
      static_dir: static/bootstrap
    - url: /
      static_files: templates/index.html
      upload: templates/index\.html
    
  8. When you're finished, the app.yaml file should look like this:

    application: your-app-id
    version: 1
    runtime: python27
    threadsafe: true
    api_version: 1
    
    handlers:
    # Endpoints handler
    - url: /js
      static_dir: static/js
    - url: /bootstrap
      static_dir: static/bootstrap
    - url: /
      static_files: templates/index.html
      upload: templates/index\.html
    - url: /_ah/spi/.*
      script: helloworld_api.APPLICATION
    
    libraries:
    - name: pycrypto
      version: latest
    - name: endpoints
      version: 1.0
    
    This completes the coding; you are ready to run and test.

Running and testing your client

  1. Change to the helloendpoints parent directory and upload the updated backend API along with your client by invoking the following:

    /appengine-sdk-installdir/google_appengine/appcfg.py update helloendpoints
    

    The first time you deploy, you may be prompted to supply your Google account email and a password before deployment is allowed. Follow the prompts to supply these. When the backend finishes deploying, a message similar to this one is displayed:

    09:08 AM Completed update of app: your-app-id, version: 1
    
  2. Visit the App Engine URL: https://<your-app-id>.appspot.com/, to display the UI:

    Hello-Endpoints

  3. Enter a 0 or 1 in the text box and click Submit to display a hardcoded Greeting from the backend API. Click Submit under List Greetings to get all the Greetings.

Next...

Continue to Adding a POST Request.

Send feedback about...

App Engine standard environment for Python