Appreciate the Magic by Learning the Trick (Building the Express Router)

Greg Filipczak
Jul 24, 2017 · 3 min read

So I stumbled over this recently. Funny stuff if you’re learning Javascript. Credit to Jose Aguinaga.

This really resonates with me right now. Here’s another noun followed by JS that you should know right now. It’s overwhelming, and it feels like there’s a really shallow understanding at times. That’s why it can be important to take a step back every once in a while to dig a little deeper into your favorite tools. You’ll learn more efficiently and you’ll appreciate the trick even more once you find out what’ actually going on.

When I was first learning to program, a friend recommended that I start with Rails after learning the basics of Python. Following Michael Hartl’s Ruby on Rails Tutorial, I eventually pushed up a hacky app with what I now realize to be an astonishing amount of functionality. Rails is the best! It’s magic!

It was within ten minutes of my first debugging session, though, that I realized the fault in this logic. Wait, what? How did my I manage to delete those records in my database? undefined method 'x' for nil:NilClass again?! Jesus. Googling issue after issue, I finally got the hang of how to make Rails do what I wanted it to do, but the understanding level was so shallow.

That was several months ago now, and I’ve since enrolled in Viking Code School’s immersive program. They’ve taken a different approach, and it’s made a striking difference in that they ask you to learn your framework by building it. We’ve had to do it with jQuery as an assignment in their prep work, and we just had to do it with Express. It’s not magic. Those folks just wrote cool code.

I won’t pretend like I was able to replicate the functionality of Express, but it was exciting being able to use Node’s built in methods to create a simple server and router wrapper that could accomplish some of what Express accomplishes.

Learn the trick — appreciate the magic

app.get('/', (req, res) => {
res.send('hello world!');
};
app.listen(3000, 'localhost', () => {
console.log(`listening on 3000`)
}

So what’s happening here. First, Express’s listen method is identical to Node’s http method:http.Server.listen() Okay, so what about the actual server? It’s actually just calling Node’s http.createServer() method! Here’s an example from the docs.

app.listen = function() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};

So that’s where the server was set up. Makes sense now. But how is it receiving requests?

exports.createServer = function createServer(requestListener) {   return new Server(requestListener); };

Oh, it just sets up a listener waiting for a ‘request’ event. Okay, that makes sense.

Knowing that, it shouldn’t be too hard to piece together a basic router! Here are some snippets from the code that my partner and I made. Credit to Viking for the basic structure of the code that we then modified.

let http = require("http");
let router = require("./router.js");
let express = () => {
let app = {
listen: function(port, host, callback) {
let server = http.createServer(router.handle);
server.listen(port, host, callback);
},
get: (path, callback) => {
router.updates(path, callback, "get");
},
post: (path, callback) => {
router.updates(path, callback, "post");
}
};
return app;
};
module.exports = express;let url = require("url");
let parser = require("./alt_parser.js");
const Router = {};Router.routes = {
get: {},
post: {}
};
Router.updates = function(path, callback, method) {
// sets the Router.routes object based on your app.get call, so that the handle function can access it later
Router.routes[method][path] = callback;
};
Router.handle = (req, res) => {
let method = req.method.toLowerCase();
let path = url.parse(req.url).pathname;
// returns the matches object from the parser. that object will validate that the route is correct and pass back a params object if route was parameterized. let matches = parser(Router.routes, path, method);
if (Router.routes[method] && matches.isTrue) {
req.params = matches.params;
Router.routes[method][matches.method](req, res);
} else {
res.end("404 Not Found");
}
};
module.exports = Router;

I won’t pretend that this code is great or that Express isn’t a fantastic resource, but I will say that the experience was extremely valuable. Routing makes so much more sense now, and it’s much more exciting writing the listen function when you know some of the amazing code behind it.

Greg Filipczak

Written by

https://github.com/gregfilipczak

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade