Overview

Skill Level: Beginner

In this tutorial, we will go a step further and show off some ways of firing requests and accessing specific pieces of information utilizing a nodeJS Microserver to host full functionality

Ingredients

  • Novice Javascript,HTML and CSS Understanding
  • NodeJS

Step-by-step

  1. Project Overview

     

    We will have two key components

    1. NodeJS microserver
    2. HTML Webpage

    We will use these componenets to accomplish our list of goals.

    1. Have NodeJS Respond with a Webpage

    2.  

      Automatically Present a File for download

    3.  

      Access and Download file via HTML Link

    4. Store and Present an image living on our server

    5.  

      Add image inline to our HTML Webpage

    6. Launch a GET Request from our Webpage

    7. Have our server respond to GET Requests.

    8. Launch a POST Request from our Webpage

    9. Have our server respond to POST Requests

     

     

     

    To Begin with let’s create some resources inside our microserver

    1. message.txt
      1. Have some string like “This is our server file”
    2. homePage.html
      1. Nothing needed for now, just create this
    3. img folder
      1. A folder called img
    4. Picture inside the img folder
  2. Input and Output Analysis

    The first thing we must do is break down each of our necessary components and understand from a data perspective what our inflows and outflows are.

     

    Our Server 

    • Takes in URL Navigation – Returns Webpage
    • Takes in a GET Request or Navigation – Returns a File downloaded
    • Takes in a GET Request or Navigation – Returns an Image
    • Takes in a GET Request w/ Param – Returns a String
    • Takes in a POST Request w/Params – Returns an Object
    • Has a folder that stores an image

    Our Webpage

    • HTML and Javascript
    • Has a section for Downloading
    • Has a section for presenting an image
    • Has a section for GET Requests
    • Has a section for POST Requests

     

  3. Server Creation

    After we have decided what we need, let’s open up our app.js.

    I like to build out my initial server components at the top of the page.

    const express = require('express'); //Require express, the lightweight server module
    const bodyParser = require("body-parser"); //Require bodyparser, a tool necessary to parse POST values
    //Initialize the app values
    const app = express();
    //Allow the app to parse values
    app.use(bodyParser.urlencoded({
    extended: true
    }));
    app.use(bodyParser.json());

    //This allows our server to host files
    app.use(express.static(__dirname + '/img'));

    ¬†All of the previous information is in my other microserver set up tutorial, however we haven’t covered the last line. Our app.use(express.static(__dirname+’/img’)); Designates a folder for us to expose externally. So any folder that is located like this <proj>/img/<file> will be callable like this <URL>/<fileName.ext>.

     

    At the very bottom of the page

    app.listen(3000, () => console.log('Example app listening on port 3000!'))

     Note that this microserver has all it needs to run. If you have done the initial steps, test by running the server and accessing your image. On your local environment, open a browser and go to the URL. It should look like this.

     

    localhost:3000/image.jpeg

     

     

     

    My url is – localhost:3000/zach.jpg

     

     

    Fig 1. Image Location

    Screen-Shot-2018-04-16-at-3.29.29-PM

     

     

    Fig 2. URL and Accessing

    Screen-Shot-2018-04-16-at-3.31.20-PM

  4. Server Paths

    Now we will be building our server path,¬†between our initial code and our end code¬†let’s build our homePage path

    //This is our homePage
    app.get('/', (req, res) => {
    //__dirname is the directory in nodeJS, useful for building paths
    res.sendFile(__dirname + '/homePage.html');
    }
    );

    Our Download URL  

    //This is our download URL
    app.get('/download',function(req, res){
    var file = __dirname + '/message.txt'; // Build absolute URI

    res.download(file); // Set disposition and send the file as a download.
    });

    Our Get Request URL

    app.get('/getResponse/:value', function (req, res){
    var value = req.params.value; //GET Parameters are passed in with this format
    res.send('Hello World. This is a GET request URL with a parameter passed in URL. The value is ' + value);
    });

    Our POST Request URL

    //This is our time request pathapp.post('/returnTime', function (req, res){  var d = new Date();  var response = {};  response.humanText = req.body.name + ' has called the returnTime request at ' + d.toDateString();  response.time = d.getTime();  response.name = req.body.name  res.send(response);  console.log('returnTime endpoint hit ' + response.humanText);}); 

     We have now built all of our necessary paths. I reccomend manually testing them all to verify and validate appropriate responses from all of them

  5. homePage.html Creation

    Now will be the biggest part of our project. We will build our initial homePage.

     

    I am providing the initial template for our homePage

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Home Page</title>
    <style>
    body { padding-top:10px; }
    </style>
    </head>
    <body>

    <div class="container">
    <div>
    <h1>HomePage</h1>
    </div>
    </div>

    <div id= 'downloadDiv' style = "border:2px; border-style: solid">
    <h2>This is our button to download a file </h2>

    <form action="/download" method="get">
    <input type="submit" value="Download via a GET Request in a html form"
    name="Submit" id="frm1_submit" />
    </form>
    <button onclick='navigateDownload()'>Navigates to Download URL in JS</button>
    </div>


    <div id= 'imageDiv' style = "border:2px; border-style: solid">
    <h2>This is where our image will be </h2>
    <image src = '/zach.jpg'></image>
    </div>

    <div id= 'requestorDiv' style = "border:2px; border-style: solid">
    <h2>This is our div to fire a GET Request</h2>
    <div>
    <button onclick = 'getRequest("/getResponse/")'>Open console and click this</button>
    </div>
    </div>

    <div id= 'updateDiv' style = "border:2px; border-style: solid; padding-bottom:20px;">
    <h2>This is our div to update our webpage</h2>
    <div>
    Enter name
    <input id ='nameBox'> </input>
    <button onclick = 'sendName()'>Send Name</button>
    <div style = 'padding-top:5px'>
    <textarea rows="2" cols="50" style = 'padding-bottom:15px; padding-top:15px; margin-left : 20px;' id = 'postResponse'> </textarea>
    </div>
    </div>
    </div>

    </body>
    </html>

    <script>

    </script>

     

  6. Download Div

    We have our download div. I am providing the code for reference

      <div id= 'downloadDiv' style = "border:2px; border-style: solid">
    <h2>This is our button to download a file </h2>

    <form action="/download" method="get">
    <input type="submit" value="Download via a GET Request in a html form"
    name="Submit" id="frm1_submit" />
    </form>
    <button onclick='navigateDownload()'>Navigates to Download URL in JS</button>
    </div>

     Inside this div we have our heading, and 2 main components. 

    1. HTML Form
      1. We use this to fire a get request
        1. action =<relativePath>
        2. method = get
      2. Has an associated button that upon selection creates the listed action in the form.
    2. Standalone Button
      1. It fires a Javascript function called navigateDownload

    Inside our Script section, let’s add our first function.

    //This function opens the webpage in a new window/tab that should auto-close and download
    function navigateDownload () {
    this.open('/download');
    }
  7. Image Div

    Inside this Div we strictly are pulling our image that we hosted on our server earlier. There should be no extra work needed if you could verify that you can reach it via your browser URL. If so this code is self explanatory

     

     <div id= 'imageDiv' style = "border:2px; border-style: solid">
    <h2>This is where our image will be </h2>
    <image src = '/zach.jpg'></image>
    </div>
  8. Get Request Div

    This Div is where we have our code for firing our Get Request and responding with data.

     

     <div id= 'requestorDiv' style = "border:2px; border-style: solid">
    <h2>This is our div to fire a GET Request</h2>
    <div>
    <button onclick = 'getRequest("/getResponse/")'>Open console and click this</button>
    </div>
    </div>

     On click we fire a Get Request and console log the response. The URL it is pointing to is the relativepath inside our onclick function.

     

    Next we will be adding to the script section.

    The clickerCount code initializes  our clickerCount. The HttpClient function is a function we call when we fire our get Request.

    The function getRequest is our actual function that builds our relative path with the clickerCount as part of our parameter passed in header to our GetRequest

     

     

     var clickerCount = 0;


    var HttpClient = function() {
    this.get = function(aUrl, aCallback) {
    var anHttpRequest = new XMLHttpRequest();
    anHttpRequest.onreadystatechange = function() {
    if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200)
    aCallback(anHttpRequest.responseText);
    }

    anHttpRequest.open( "GET", aUrl, true );
    anHttpRequest.send( null );
    }
    }



    function getRequest (relPath){
    relPath = relPath + clickerCount
    var request = new HttpClient();
    request.get(relPath, function(response) {
    //Do get Request Stuff Here
    console.log(response);
    });
    clickerCount++
    }

  9. Post Request

    Inside this Div we have our buttons and text fields.

     

    The first text field the user is supposed to enter their name. The button following it is what the user clicks to POST their name to the POST endpoint on our Microserver.

     

     <div id= 'updateDiv' style = "border:2px; border-style: solid; padding-bottom:20px;">
    <h2>This is our div to update our webpage</h2>
    <div>
    Enter name
    <input id ='nameBox'> </input>
    <button onclick = 'sendName()'>Send Name</button>
    <div style = 'padding-top:5px'>
    <textarea rows="2" cols="50" style = 'padding-bottom:15px; padding-top:15px; margin-left : 20px;' id = 'postResponse'> </textarea>
    </div>
    </div>

    ¬†After we have created the initial HTML, we can finish off our javascript components that we call. Essentially we get the value of the entered text, convert the parameters to URI components, and send in the body. Upon detection of a successful call, we change the textArea’s value to the humanText from our microserver

    function postRequest (url,params) {

    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);

    //Code to convert JSON to URI Componenet
    var query = "";
    for (key in params) {
    query += encodeURIComponent(key)+"="+encodeURIComponent(params[key])+"&";
    }

    //Send the proper header information along with the request
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    xhr.send(query);

    xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    //Succesful Response detected run code below
    console.log(this.responseText);
    var response = JSON.parse(this.responseText);
    if(response.humanText){
    document.getElementById('postResponse').value = response.humanText;
    console.log(response.humanText);
    }

    }
    };


    }


    function sendName(){
    var name = document.getElementById('nameBox').value;
    var params = {};
    params.name = name;
    postRequest('/returnTime',params);
    }
  10. End Result

    Our Page is now finished. The first two buttons should return the file. The second section should have our picture. The third section should log get request information in our browser console. The fourth section should take in our name from the first box, and upon clicking the button log some information in our second box.

    Screen-Shot-2018-04-16-at-4.11.59-PM

  11. Questions

    For any further questions please reach out to me at zachary.silverstein@ibm.com

Join The Discussion