A web client that consumes the API

We are going to put together an ultra simple web client that consumes the capabilities and data exposed through our API, allowing users to interact with the polling system we built in the previous chapter and earlier in this chapter. Our client will be made up of three web pages:

  • An index.html page that shows all the polls
  • A view.html page that shows the results of a specific poll
  • A new.html page that allows users to create new polls

Create a new folder called web alongside the api folder and add the following content to the main.go file:

package main 
import ( 
  "flag" 
  "log" 
  "net/http" 
) 
func main() { 
  var addr = flag.String("addr", ":8081", "website address") 
  flag.Parse() 
  mux := http.NewServeMux() 
  mux.Handle("/", http.StripPrefix("/",  
    http.FileServer(http.Dir("public")))) 
  log.Println("Serving website at:", *addr) 
  http.ListenAndServe(*addr, mux) 
} 

These few lines of Go code really highlight the beauty of the language and the Go standard library. They represent a complete, highly scalable, static website hosting program. The program takes an addr flag and uses the familiar http.ServeMux type to serve static files from a folder called public.

Tip

Building the next few pages –while we're building the UI –consists of writing a lot of HTML and JavaScript code. Since this is not Go code, if you'd rather not type it all out, feel free to head over to the GitHub repository for this book and copy and paste it from https://github.com/matryer/goblueprints. You are also free to include the latest versions of the Bootstrap and jQuery libraries as you see fit, but there may be implementation differences with subsequent versions.

Index page showing a list of polls

Create the public folder inside web and add the index.html file after writing the following HTML code in it:

<!DOCTYPE html> 
<html> 
<head> 
  <title>Polls</title> 
  <link rel="stylesheet"
   href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/     
    bootstrap.min.css"> 
</head> 
<body> 
</body> 
</html> 

We will use Bootstrap again to make our simple UI look nice, but we need to add two additional sections to the body tag of the HTML page. First, add the DOM elements that will display the list of polls:

<div class="container"> 
  <div class="col-md-4"></div> 
  <div class="col-md-4"> 
    <h1>Polls</h1> 
    <ul id="polls"></ul> 
    <a href="new.html" class="btn btn-primary">Create new poll</a> 
  </div> 
  <div class="col-md-4"></div> 
</div> 

Here, we are using Bootstrap's grid system to center-align our content that is made up of a list of polls and a link to new.html, where users can create new polls.

Next, add the following script tags and JavaScript underneath that:

<script  src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 <script> 
  $(function(){ 
    var update = function(){ 
      $.get("http://localhost:8080/polls/?key=abc123", null, null,  "json") 
        .done(function(polls){ 
          $("#polls").empty(); 
          for (var p in polls) { 
            var poll = polls[p]; 
            $("#polls").append( 
              $("<li>").append( 
                $("<a>") 
                  .attr("href", "view.html?poll=polls/" + poll.id) 
                  .text(poll.title) 
              ) 
            ) 
          } 
        } 
      ); 
      window.setTimeout(update, 10000); 
    } 
    update(); 
  }); 
</script> 

We are using jQuery's $.get function to make an AJAX request to our web service. We are hardcoding the API URL –which, in practice, you might decide against –or at least use a domain name to abstract it. Once the polls have loaded, we use jQuery to build up a list containing hyperlinks to the view.html page, passing the ID of the poll as a query parameter.

Creating a new poll

To allow users to create a new poll, create a file called new.html inside the public folder, and add the following HTML code to the file:

<!DOCTYPE html> 
<html> 
<head> 
  <title>Create Poll</title> 
  <link rel="stylesheet"       
    href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/
    bootstrap.min.css"> 
</head> 
<body> 
  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">   </script> 
</body> 
</html> 

We are going to add the elements for an HTML form that will capture the information we need when creating a new poll, namely the title of the poll and the options. Add the following code inside the body tags:

<div class="container"> 
  <div class="col-md-4"></div> 
  <form id="poll" role="form" class="col-md-4"> 
    <h2>Create Poll</h2> 
    <div class="form-group"> 
      <label for="title">Title</label> 
      <input type="text" class="form-control" id="title" 
        placeholder="Title"> 
    </div> 
    <div class="form-group"> 
      <label for="options">Options</label> 
      <input type="text" class="form-control" id="options"
        placeholder="Options"> 
      <p class="help-block">Comma separated</p> 
    </div> 
    <button type="submit" class="btn btn-primary">
      Create Poll</button> or <a href="/">cancel</a> 
  </form> 
  <div class="col-md-4"></div> 
</div> 

Since our API speaks JSON, we need to do a bit of work to turn the HTML form into a JSON-encoded string and also break the comma-separated options string into an array of options. Add the following script tag:

<script> 
  $(function(){ 
    var form = $("form#poll"); 
    form.submit(function(e){ 
      e.preventDefault(); 
      var title = form.find("input[id='title']").val(); 
      var options = form.find("input[id='options']").val(); 
      options = options.split(","); 
      for (var opt in options) { 
        options[opt] = options[opt].trim(); 
      } 
      $.post("http://localhost:8080/polls/?key=abc123", 
        JSON.stringify({ 
          title: title, options: options 
        }) 
      ).done(function(d, s, r){ 
        location.href = "view.html?poll=" +
        r.getResponseHeader("Location"); 
      }); 
    }); 
  }); 
</script> 

Here, we add a listener to the submit event of our form and use jQuery's val method to collect the input values. We split the options with a comma and trim the spaces away before using the $.post method to make the POST request to the appropriate API endpoint. JSON.stringify allows us to turn the data object into a JSON string, and we use that string as the body of the request, as expected by the API. On success, we pull out the Location header and redirect the user to the view.html page, passing a reference to the newly created poll as the parameter.

Showing the details of a poll

The final page of our app we need to complete is the view.html page, where users can see the details and live results of the poll. Create a new file called view.html inside the public folder and add the following HTML code to it:

<!DOCTYPE html> 
<html> 
<head> 
  <title>View Poll</title> 
  <link rel="stylesheet" 
   href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> 
</head> 
<body> 
  <div class="container"> 
    <div class="col-md-4"></div> 
    <div class="col-md-4"> 
      <h1 data-field="title">...</h1> 
      <ul id="options"></ul> 
      <div id="chart"></div> 
      <div> 
        <button class="btn btn-sm" id="delete">Delete this poll</button> 
      </div> 
    </div> 
    <div class="col-md-4"></div> 
  </div> 
</body> 
</html> 

This page is mostly similar to the other pages; it contains elements to present the title of the poll, the options, and a pie chart. We will be mashing up Google's Visualization API with our API to present the results. Underneath the final div tag in view.html (and above the closing body tag), add the following script tags:

<script src="//www.google.com/jsapi"></script> 
<script  src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script> 
<script> 
google.load('visualization', '1.0', {'packages':['corechart']}); 
google.setOnLoadCallback(function(){ 
  $(function(){ 
    var chart; 
    var poll = location.href.split("poll=")[1]; 
    var update = function(){ 
      $.get("http://localhost:8080/"+poll+"?key=abc123", null, null,
        "json") 
        .done(function(polls){ 
          var poll = polls[0]; 
          $('[data-field="title"]').text(poll.title); 
          $("#options").empty(); 
          for (var o in poll.results) { 
            $("#options").append( 
              $("<li>").append( 
                $("<small>").addClass("label label 
                default").text(poll.results[o]), 
                " ", o 
              ) 
            ) 
          } 
          if (poll.results) { 
            var data = new google.visualization.DataTable(); 
            data.addColumn("string","Option"); 
            data.addColumn("number","Votes"); 
            for (var o in poll.results) { 
              data.addRow([o, poll.results[o]]) 
            } 
            if (!chart) { 
              chart = new                 google.visualization.PieChart 
                (document.getElementById('chart')); 
            } 
            chart.draw(data, {is3D: true}); 
          } 
        } 
      ); 
      window.setTimeout(update, 1000); 
    }; 
    update(); 
    $("#delete").click(function(){ 
      if (confirm("Sure?")) { 
        $.ajax({ 
          url:"http://localhost:8080/"+poll+"?key=abc123", 
          type:"DELETE" 
        }) 
        .done(function(){ 
          location.href = "/"; 
        }) 
      } 
    }); 
  }); 
}); 
</script> 

We include the dependencies we will need in order to power our page, jQuery and Bootstrap, and also the Google JavaScript API. The code loads the appropriate visualization libraries from Google and waits for the DOM elements to load before extracting the poll ID from the URL by splitting it on poll=. We then create a variable called update that represents a function responsible for generating the view of the page. This approach is taken to make it easy for us to use window.setTimeout in order to issue regular calls to update the view. Inside the update function, we use $.get to make a GET request to our /polls/{id} endpoint, replacing {id} with the actual ID we extracted from the URL earlier. Once the poll has loaded, we update the title on the page and iterate over the options to add them to the list. If there are results (remember, in the previous chapter, the results map was only added to the data as votes started being counted), we create a new google.visualization.PieChart object and build a google.visualization.DataTable object containing the results. Calling draw on the chart causes it to render the data and thus update the chart with the latest numbers. We then use setTimeout to tell our code to call update again in another second.

Finally, we bind to the click event of the delete button we added to our page, and after asking the user whether they are sure, make a DELETE request to the polls URL and then redirect them back to the home page. It is this request that will actually cause the OPTIONS request to be made first, asking for permission, which is why we added explicit support for it in our handlePolls function earlier.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.231.15