WebFund 2016W Lecture 9: Difference between revisions
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..." |
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...
andvar_route_list...
functions in order to avoid the generation of “Type Error: the Route is not a function error.
- Must follow the definition of
// 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 theroutes
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
- Note the
//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
- Error #1:
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 thejade_options
object
- Generated because there was a comma missing at the end of title:
- Error #2:
- 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
- e.g the
- 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