WebFund 2016W Lecture 9: Difference between revisions

From Soma-notes
Created page with "==Video== The video from the lecture given on February 4, 2016 [http://homeostasis.scs.carleton.ca/~soma/webfund-2016w/lectures/comp2406-2016w-lec09-04Feb2016.mp4 is now avai..."
 
LeeCroft (talk | contribs)
No edit summary
 
Line 5: Line 5:
==Notes==
==Notes==


==Code==
===Agenda===
 
*We are now a week away from the midterm (February 11th, 2016)
*The solutions for Assignment 3 will be reviewed in class on Tuesday, February 9th
*In this class the focus was on extending the functionality of tinyweb.js to that of form-demo.js and examforms.js in lieu of introducing new topics before the midterm
 
===Version Control===
 
*Question: How many people have used CVS or Github previously? Has version control been covered in previous courses?
**Majority of class indicated that version control has not been a topic covered in previous courses.
*Pros of version control:
**The ability to create backups and branch code
**Github is a great resource for powerful collaboration, code review, and code management for open source and private projects. Public projects are always free. (https://github.com/ )
*Git was originally developed for the Linux kernel.
*Code Academy has a Github tutorial - https://www.codecademy.com/learn/learn-git
 
*Diff command was recommended – analyzes two files and prints the lines that different. (diff file1.js file2.js) 
**e.g diff ~/Documents/Class/WebFund/2016W/code tinwebserver.js tinywebserver_solution
 
===tinyweb.js vs form-demo.js===
*They can both serve static files
*tinyweb.js:
**tinyweb.js serves static content from the directory specified as the options directory
**A file on disk is served for a particular URL. As a result, the content always remains the same (static content)
*form-demo.js:
**form-demo serves static content form a public directory
**Can handle form submissions... this depends upon handling dynamic content since the whole point is to change the state of the web server
**Supports jade templates
**Can run code to generate pages... meaning that there are functions that are run every time a request is made for a particular URL (dynamic content)
***e.g in form-demo/routes/index.js:
 
<code><pre>
router.get('/', function(req, res, next) {
  res.render('index', { title: 'COMP 2406 Simple form demo' });
});
</pre></code>
 
===Coding Exercise - Adding More Functionality To tinyweb.js===
*To get started, it’s better to initially create data structures and then create code to support the data structures
*First step of emulating form-demo was to create the framework for the routing functions (‘/’ , ‘/add’, “/list’).
**Must follow the definition of <code>var route_get...</code>, <code>var route_post...</code> and <code>var_route_list...</code> functions in order to avoid the generation of “Type Error: the Route is not a function error.
 
<code><pre>
// routes is a mapping of the url’s we want to come in and the code we want to run when the url’s are run.
var routes = {
  ‘/’: route_index,
  ‘/add’ : route_add,
  ‘/list’ : route_list
}
</pre></code>
 
*The following code was copied from index.js:
 
<code><pre>
router.get('/', function(req, res, next) {
  res.render('index', { title: 'COMP 2406 Simple form demo' });
});
router.post('/add', function(req, res) {
  var obj = { name: req.body.name,
      city: req.body.city,
              country: req.body.country,
              birthday: req.body.birthday,
              email: req.body.email };
  state.push(obj);
  res.render('add', { title: 'Person just added', item: obj });
});
router.get('/list', function(req, res) {
  res.render('list', { title: 'People Listing',  items: state});
});
</pre></code>
 
*The above code was pasted into tinyweb-forms.js after <code>var options;</code> and before the definition of the <code>routes</code> object
*The code was adapted as shown below
**Note the <code>next</code> argument was removed from functions since this argument is not needed in our version
 
<code><pre>
//The purpose of these functions is to render a template using jade and respond with the rendered HTML
//We will be making modifications to achieve this
 
//This one has been partially changed and now provides a response with a static web page
var route_index  = function(req, res) {
  //res.render('index', { title: 'COMP 2406 Simple form demo' });
  respond(req, res, 200, “<html><body><h1>Success!</h1></body></html>”,”text/html”); //tiny web page
}
var route_add = (function(req, res) {
  var obj = { name: req.body.name,
      city: req.body.city,
              country: req.body.country,
              birthday: req.body.birthday,
              email: req.body.email };
  state.push(obj);
  res.render('add', { title: 'Person just added', item: obj });
}
var route_list = (function(req, res) {
  res.render('list', { title: 'People Listing',  items: state});
}
</pre></code>
 
*To get the above functions called, the code to tinyweb_forms.js was modified in the <code>request_handler</code> function just after the following if statement:
 
<code><pre>
if(options.aliases.hasOwnProperty(url)){
  myConsole.log(“Aliasing “ + url + “ to “ + options.aliases[url]);
  url = options.aliases[url];
}
</pre></code>
 
*The code that was added is:
 
<code><pre>
if (routes.hasOwnProperty(url)) {
  theRoute = routes[url]; // look it up and send the info the return and response
  return theRoute(request, response); // arguments used from var request_handler
}
</pre></code>
 
*We do not use the serve file function since we are generating content dynamically
*To make sure the code ran correctly, the tinyweb-options.json, error.html and tinyweb-forms.js files were moved to the same folder
*Furthermore, the tinyweb-options.json file was modified from
 
<code><pre>
{
  “host”: “localhost”,
  “port”: 8000,
  ”index”: ”index.html”,
  ”docroot” : “.”,
  “logged-headers”: [”user-agent”, “referrer”],
  ”errorpage”: ”error.html”,
  ”aliases”: {
”/index.html”: “/hello.html”,
“/”: “/hello.html”,
“/really/cool.html”: “/notcool.html”
  }
}
</pre></code>
 
*To:
 
<code><pre>
{
  “host”: “localhost”,
  “port”: 8000,
  ”index”: ”index.html”,
  ”docroot” : “.”,
  “logged-headers”: [”user-agent”, “referrer”],
  ”errorpage”: ”error.html”,
  ”aliases”: {
”/index.html”: “/”,
“/hello.html”: “/”,
“/really/cool.html”: “/notcool.html”
  }
}
</pre></code>
 
*In order to render the Jade template, the following line was added at the top of the script:
 
<code><pre>var jade = require(‘jade’);</pre></code>
 
*In order to load Jade in this way, you must run the following command in the folder that contains the tinyweb-forms files:
 
<code><pre>npm install jade</pre></code>
 
*A node_modules sub folder will be created
*The jade files from form-demo/views(templates) can now be moved over to the tinyweb-forms folder (main folder)
*The <code>route_index</code> function is then modified as follows to in order to use the Jade template
**Note that an async function is used to ensure this is done in a non-blocking fashion... we want the webserver to remain responsive for other incoming requests
 
<code><pre>
var route_index  = function(req, res) {
 
  var content, template, options;
 
  var render_template = function(err, template){
      content = jade.render(template, options);
      respond(req, res, 200, content, ”text/html”);
  }
 
  options = {pretty: true,
              title: 'COMP 2406 Tinyweb Forms Demo'};
 
  return fs.readFile(“index.jade”, ”utf-8”, render_template);
}
</pre></code>
 
*When the code above was run errors that were generated were:
**Error #1:
***Error: Jade:1
***>1 extends layout….the “filename” option is required to use ”extends” with ””relative” paths... because it doesn’t know what file to load
**Solution #1: add a reference to index.jade
 
<code><pre>
var route_index = function(req, res) {
 
  var content, template, options;
 
  var render_template = function(err, template){
      content = jade.render(template, jade_options);
      respond(req, res, 200, content,”text/html”);
  }
 
  jade_options = {pretty: true,
                  title: 'COMP 2406 Tinyweb Forms Demo',
                  filename: ‘index.jade’};
 
  return fs.readFile(jade_options.filename, ”utf-8”, render_template);
}
 
// The calls to fs.readFile(), jade.render() and respond() are all needed to get the functionality of the res.render() which was contained exam-forms
</pre></code>
 
**Error #2:
***A 404 error was generated for style.css
**Solution #2:
***Copy the stylesheet over to the form-demo folder
***Once this was done, prettier fonts were generated and the 404 error was no longer generated
**Error and Solution #3: Unexpected identifier
***Generated because there was a comma missing at the end of title: <code>'COMP 2406 Tinyweb Forms Demo',</code> in the <code>jade_options</code> object
*Next, we moved on to modifying code to redirect the /add route to /list
 
<code><pre>
var route_add = (function(req, res) {
  // var obj = { name: req.body.name,
  //   city: req.body.city,
  //            country: req.body.country,
  //            birthday: req.body.birthday,
  //            email: req.body.email };
  //state.push(obj);
  //res.render('add', { title: 'Person just added', item: obj });
 
  myConsole.log(“302” + “\t” + req.method + “\t”  + req.url);
 
  res.writeHead(302, {
      “Content-Type”: “text/html”
      “Location”: “/list”
  });
  return res.end();
  respond(req, res, 200, content, “text/html”);
}
var route_list = (function(req, res) {
  res.render('list', { title: 'People Listing',  items: state});
}
</pre></code>
 
*By setting the appropriate HTTP response code and response headers, we indicate to the client's browser that it should make another request in order to achieve the redirection
*In examforms.js, <code>res.redirect(‘/list’);</code> handles this same functionality for redirection
 
====To Summarize====
 
*The changes that we made in this exercise include:
**Giving tinyweb the ability to run code to dynamically generate response for incoming requests
**Bringing in the functionality to render templates and respond with the rendered HTML
**Implementing redirection in response to some requests
*The code in this exercise does not:
**Save the state of the data (the data does not persist after the server is shut down)
**Store the state object (the people added in the form)
**Render the contents of the list
 
===Additional Notes===
*Don’t use globals for data unless you are thinking explicitly that the data will be shared
**e.g the <code>state</code> array used in this code may not be well-suited as a global variable
*Web servers have databases so that they can persistently store their data (don’t want the data to go away) and concurrently access the data
**This is a better alternative for storing the state data
*The code modifications made in this exercise to bridge the gap between tinyweb.js and examforms.js were very specific
**examforms.js is far more robust in terms of how it’s coded

Latest revision as of 05:42, 9 February 2016

Video

The video from the lecture given on February 4, 2016 is now available.

Notes

Agenda

  • We are now a week away from the midterm (February 11th, 2016)
  • The solutions for Assignment 3 will be reviewed in class on Tuesday, February 9th
  • In this class the focus was on extending the functionality of tinyweb.js to that of form-demo.js and examforms.js in lieu of introducing new topics before the midterm

Version Control

  • Question: How many people have used CVS or Github previously? Has version control been covered in previous courses?
    • Majority of class indicated that version control has not been a topic covered in previous courses.
  • Pros of version control:
    • The ability to create backups and branch code
    • Github is a great resource for powerful collaboration, code review, and code management for open source and private projects. Public projects are always free. (https://github.com/ )
  • Git was originally developed for the Linux kernel.
  • Code Academy has a Github tutorial - https://www.codecademy.com/learn/learn-git
  • Diff command was recommended – analyzes two files and prints the lines that different. (diff file1.js file2.js)
    • e.g diff ~/Documents/Class/WebFund/2016W/code tinwebserver.js tinywebserver_solution

tinyweb.js vs form-demo.js

  • They can both serve static files
  • tinyweb.js:
    • tinyweb.js serves static content from the directory specified as the options directory
    • A file on disk is served for a particular URL. As a result, the content always remains the same (static content)
  • form-demo.js:
    • form-demo serves static content form a public directory
    • Can handle form submissions... this depends upon handling dynamic content since the whole point is to change the state of the web server
    • Supports jade templates
    • Can run code to generate pages... meaning that there are functions that are run every time a request is made for a particular URL (dynamic content)
      • e.g in form-demo/routes/index.js:
router.get('/', function(req, res, next) {
   res.render('index', { title: 'COMP 2406 Simple form demo' });
});

Coding Exercise - Adding More Functionality To tinyweb.js

  • To get started, it’s better to initially create data structures and then create code to support the data structures
  • First step of emulating form-demo was to create the framework for the routing functions (‘/’ , ‘/add’, “/list’).
    • Must follow the definition of var route_get..., var route_post... and var_route_list... functions in order to avoid the generation of “Type Error: the Route is not a function error.
// routes is a mapping of the url’s we want to come in and the code we want to run when the url’s are run.
var routes = {
   ‘/’: route_index,
   ‘/add’ : route_add,
   ‘/list’ : route_list
}
  • The following code was copied from index.js:
router.get('/', function(req, res, next) {
   res.render('index', { title: 'COMP 2406 Simple form demo' });
});
 
router.post('/add', function(req, res) {
   var obj = { name: req.body.name,
	       city: req.body.city,
               country: req.body.country,
               birthday: req.body.birthday,
               email: req.body.email };
   state.push(obj);
   res.render('add', { title: 'Person just added', item: obj });
});
 
router.get('/list', function(req, res) {
   res.render('list', { title: 'People Listing',  items: state});
});
  • The above code was pasted into tinyweb-forms.js after var options; and before the definition of the routes object
  • The code was adapted as shown below
    • Note the next argument was removed from functions since this argument is not needed in our version
//The purpose of these functions is to render a template using jade and respond with the rendered HTML
//We will be making modifications to achieve this

//This one has been partially changed and now provides a response with a static web page
var route_index  = function(req, res) {
   //res.render('index', { title: 'COMP 2406 Simple form demo' });
   respond(req, res, 200, “<html><body><h1>Success!</h1></body></html>”,”text/html”); //tiny web page 
}
 
var route_add = (function(req, res) {
   var obj = { name: req.body.name,
	       city: req.body.city,
               country: req.body.country,
               birthday: req.body.birthday,
               email: req.body.email };
   state.push(obj);
   res.render('add', { title: 'Person just added', item: obj });
}
 
var route_list = (function(req, res) {
   res.render('list', { title: 'People Listing',  items: state});
}
  • To get the above functions called, the code to tinyweb_forms.js was modified in the request_handler function just after the following if statement:
if(options.aliases.hasOwnProperty(url)){
   myConsole.log(“Aliasing “ + url + “ to “ + options.aliases[url]);
   url = options.aliases[url];
}
  • The code that was added is:
if (routes.hasOwnProperty(url)) {
   theRoute = routes[url]; // look it up and send the info the return and response
   return theRoute(request, response); // arguments used from var request_handler
}
  • We do not use the serve file function since we are generating content dynamically
  • To make sure the code ran correctly, the tinyweb-options.json, error.html and tinyweb-forms.js files were moved to the same folder
  • Furthermore, the tinyweb-options.json file was modified from
{
   “host”: “localhost”,
   “port”: 8000,
   ”index”: ”index.html”,
   ”docroot” : “.”,
   “logged-headers”: [”user-agent”, “referrer”],
   ”errorpage”: ”error.html”,
   ”aliases”: {
 	”/index.html”: “/hello.html”,
 	“/”: “/hello.html”,
	“/really/cool.html”: “/notcool.html”
   }
}
  • To:
{
   “host”: “localhost”,
   “port”: 8000,
   ”index”: ”index.html”,
   ”docroot” : “.”,
   “logged-headers”: [”user-agent”, “referrer”],
   ”errorpage”: ”error.html”,
   ”aliases”: {
 	”/index.html”: “/”,
 	“/hello.html”: “/”,
	“/really/cool.html”: “/notcool.html”
   }
}
  • In order to render the Jade template, the following line was added at the top of the script:
var jade = require(‘jade’);
  • In order to load Jade in this way, you must run the following command in the folder that contains the tinyweb-forms files:
npm install jade
  • A node_modules sub folder will be created
  • The jade files from form-demo/views(templates) can now be moved over to the tinyweb-forms folder (main folder)
  • The route_index function is then modified as follows to in order to use the Jade template
    • Note that an async function is used to ensure this is done in a non-blocking fashion... we want the webserver to remain responsive for other incoming requests
var route_index  = function(req, res) {
  
   var content, template, options;

   var render_template = function(err, template){
      content = jade.render(template, options);
      respond(req, res, 200, content, ”text/html”); 
   }

   options = {pretty: true,
              title: 'COMP 2406 Tinyweb Forms Demo'};

   return fs.readFile(“index.jade”, ”utf-8”, render_template);
}
  • When the code above was run errors that were generated were:
    • Error #1:
      • Error: Jade:1
      • >1 extends layout….the “filename” option is required to use ”extends” with ””relative” paths... because it doesn’t know what file to load
    • Solution #1: add a reference to index.jade
var route_index = function(req, res) {
  
   var content, template, options;

   var render_template = function(err, template){
      content = jade.render(template, jade_options);
      respond(req, res, 200, content,”text/html”); 
   }

   jade_options = {pretty: true,
                   title: 'COMP 2406 Tinyweb Forms Demo',
                   filename: ‘index.jade’};

   return fs.readFile(jade_options.filename, ”utf-8”, render_template);
}

// The calls to fs.readFile(), jade.render() and respond() are all needed to get the functionality of the res.render() which was contained exam-forms
    • Error #2:
      • A 404 error was generated for style.css
    • Solution #2:
      • Copy the stylesheet over to the form-demo folder
      • Once this was done, prettier fonts were generated and the 404 error was no longer generated
    • Error and Solution #3: Unexpected identifier
      • Generated because there was a comma missing at the end of title: 'COMP 2406 Tinyweb Forms Demo', in the jade_options object
  • Next, we moved on to modifying code to redirect the /add route to /list
var route_add = (function(req, res) {
   // var obj = { name: req.body.name,
   //		  city: req.body.city,
   //             country: req.body.country,
   //             birthday: req.body.birthday,
   //             email: req.body.email };
   //state.push(obj);
   //res.render('add', { title: 'Person just added', item: obj });

   myConsole.log(“302” + “\t” + req.method + “\t”  + req.url);

   res.writeHead(302, {
       “Content-Type”: “text/html”
       “Location”: “/list”
   });
   return res.end();
 
   respond(req, res, 200, content, “text/html”);
}
 
var route_list = (function(req, res) {
   res.render('list', { title: 'People Listing',  items: state});
}
  • By setting the appropriate HTTP response code and response headers, we indicate to the client's browser that it should make another request in order to achieve the redirection
  • In examforms.js, res.redirect(‘/list’); handles this same functionality for redirection

To Summarize

  • The changes that we made in this exercise include:
    • Giving tinyweb the ability to run code to dynamically generate response for incoming requests
    • Bringing in the functionality to render templates and respond with the rendered HTML
    • Implementing redirection in response to some requests
  • The code in this exercise does not:
    • Save the state of the data (the data does not persist after the server is shut down)
    • Store the state object (the people added in the form)
    • Render the contents of the list

Additional Notes

  • Don’t use globals for data unless you are thinking explicitly that the data will be shared
    • e.g the state array used in this code may not be well-suited as a global variable
  • Web servers have databases so that they can persistently store their data (don’t want the data to go away) and concurrently access the data
    • This is a better alternative for storing the state data
  • The code modifications made in this exercise to bridge the gap between tinyweb.js and examforms.js were very specific
    • examforms.js is far more robust in terms of how it’s coded