Routing Functions

In notebook:
FrontEndMasters Organising Javascript functionality
Created at:
2016-10-10
Updated:
2016-10-11
Tags:
libraries React JavaScript
How to do routing without a framework. He pushes routes the same way as you would push middleware functions into an Express app. 
Same concept as ​app.use​ or ​app.get​, but his API is ​routes.push​.
  // server.js

// setup HTTP routes
routes.push(
	// always set server name
	function serverName(req,res) {
		res.setHeader("Server",secret.SERVER_NAME);
	}
);
Each route function receives a ​req​ and ​res​ parameters and it decides if it should act on it or not. 
So each route come one after the other. 

Talks about the security headers in server.js.

Another route from server.js:
  routes.push(
	// await full request
	function fullRequest(req,res) {
		req.body = "";
		return ASQ.react(function listener(next){
			req.addListener("data",function(chunk){
				req.body += chunk;
			});
			req.addListener("end",next);
			req.resume();
		});
	}
);
This route is waiting for the entire request to come in, if it's more than one chunk. He sets up a data listener ​addListener​ to compose the chunks. 

Then a route for favicon (for Chrome). When the browser ask for the favicon he returns a catchable 204 response to stop the browser asking for it. :
  routes.push(
	// favicon
	function favicon(req,res) {
		try {
			if (req.method === "GET" && req.url === "/favicon.ico") {
				fs.statSync(path.join(__dirname,"web","favicon.ico"));
			}
			return;
		}
		catch (err) {}

		// empty favicon.ico response
		res.writeHead(204,{
			"Content-Type": "image/x-icon",
			"Cache-Control": "public, max-age: 604800"
		});
		res.end();
		return true;
	}
)

Then handle static files (static files modules). It's the same static file server that comes with Express:
  routes.push(
	// static file request?
	function staticResources(req,res) {
		if (req.method === "GET" &&
			/^\/(?:js\/(?=.+)|css\/(?=.+)|images\/(?=.+)|robots\.txt\b|humans\.txt\b|favicon\.ico\b)/
			.test(req.url)
		) {
			req.url = "/web" + req.url;
			static_files.serve(req,res);
			return true;
		}
	}
);
The last route if none of the others have taken over is for a full page load:
  routes.push(
	// a recognized full-page request?
	function loadPage(req,res) {
		var url;

		if (
		  // NOTE: check if it's a GET request and
		  // if it's a route that the server can handle
		  // i.e. it knows how to render that page
			req.method === "GET" &&
			(url = Pages.recognize(req.url))
		) {
			return ASQ(function ASQ(done){
					View.getPageHTML(url)
					.val(function pageHTML(url,html) {
						res.writeHead(200,{ "Content-type": "text/html; charset=UTF-8" });
						res.end(html);
						done(true);
					})
					.or(done.fail);
				});
		}
	}
);
Finally the default route of 404...
  routes.push(
	// default route
	function defaultRoute(req,res) {
		res.writeHead(404);
		res.end();
	}
);
So how does this routes array work?
Express does an internal ​for​ loop of routes.
Kyle created the ​router​ generator function:
  function *router(token) {
	var req = token.messages[0], res = token.messages[1], route, error;

	for (route of routes) {
		try {
			route = route(req,res);
			if (ASQ.isSequence(route)) {
				// wait to resolve the route
				route = yield route;
			}
			if (route === true) { break; }
		}
		catch (err) { .. }
	}

	// response error?
	if (error) {
		throw {	.. };
	}
}
He can stop/pause the local execution with ​yield​. 
Line#7 : if the route function returns a promise (or an asequence object – from his async library), then wait for it to finish (​yield​). 
Line#11: if one of the routes function can handle that route and returns ​true​ then it can break out of the loop and not try the remaining routes functions.

He can use ​try/catch​ inside the generator function. 

Talks about the ​runner​ helper that runs the generator function to completion. :
  // server request handling
ASQ.react(function listen(trigger){
	httpserv.on("request",trigger);
})
.runner(router)
.or(responseError);
If an error happens in ​runner​ (line#5), it will be bubble out to ​responseError​. :
  function responseError(respErr) {
	try {
		if (respErr.req && respErr.res) {
			if (respErr.req.headers &&
				respErr.req.headers["accept"] === "application/json"
			) {
				respErr.reason = JSON.stringify({
					error: respErr.reason
				});
			}
			respErr.res.writeHead(500);
			respErr.res.end(respErr.reason.toString());
			return true;
		}
	} catch(e) {}

	ERROR("responseError",
		respErr ? ((respErr.stack + "") || respErr.toString()) : "Unknown response error"
	);
}
Basically, if it received a JSON request, it will reply with a JSON, otherwise it will just log the error. 

All the errors will bubble here, from anywhere in the machinery.