Let’s build a NodeJS micro framework (Part I)

Learning to build an express like NodeJS framework …

Frameworks and libraries are great pieces of software we rely on to build awesome products. As software developers, knowing how they work from the ground up can help us develop better software. In this three-part tutorial series, I will guide you through the implementation of an express like web framework, while we won’t implement all the ins and outs of the express framework, we will implement two of the most important components of a micro framework.
By the end of this tutorial, you will have a working framework providing the following high-level features: URL routing, middleware support, template rendering with inheritance. I have creatively named the framework micro, sweet name, right?

We all agree that practicing is the best way to master whatever skill we want to acquire. I highly encourage you to fire up Vim, VSCode or whatever you are comfortable with writing code.

Notes:

Ready, set, let’s go!!!

To build a developer friendly framework, we first need to think about the API. How will software developers use it? With the plethora of frameworks at our disposal to get inspiration from, this should be the easiest thing to do. Our implementation will closely mimic the express framework API.

First of all, import the framework and instantiate it as app passing config parameters:

We access the routermember of the framework instance to set up a route handler. The all method will set up a handler that handles most HTTP verbs (e.i GET, POST, PUT, DELETE). This can be useful for an API landing page. Such a page can help test availability status. It can also be used to display miscellaneous info such as version, vendor, etc…

To get access to the full router API, the application route method is the way to go. It gives access to the full router instance of the app. Also, note the use of the render method on the HTTP response. This is the only API for using the template engine. I won’t go into the template engine syntax for now. The rest of the snippet shows all you can do with the router component.

Now that we all know the Micro framework API, we can create our project and start coding. I will assume you can npm init, giving any name to your project. I have decided to name mine njs-micro. Make sure your project has the following structure.

    /njs-micro
    │   README.md  
    │
    └───/src
    │   │   index.js
    │   │   micro.js
    │   │   router.js
    │   │   templater.js
    │   │
    └───/test
    │   │   ...
    │   
    └───/templates
        │   index.html
        │   main.html

Now open njs-micro/src/micro.js, and let’s code the core class of our micro framework.

The imports at the top already show that we will need the NodeJS HTTP module as well as the router and template modules. The Micro class has a few methods that we will describe and implement one at a time. The methods meant for internal use start with an underscore. Let’s implement the constructor.

As you can see, we first create defaults config for the instance and combine it with the configuration provided by the instantiator (developer). It’s important to know that configuration from the instantiator take precedence.
The next thing we do is create a bare metal NodeJS HTTP server as a private member of the class: _httpServer. By passing the _handlerRequest method as the HTTP request handler, every time the application receives a request, this method will be invoked. The last two things the constructor takes care of are: Instantiating a router and a template engine. The template engine needs to know the templates folder as well as the application runtime environment for basic optimization purpose.

Next is the boot method that will start the internal HTTP server. Some frameworks might call this method run. Here we just call the listen method of the NodeJS HTTP server. The callback parameter is checked to make sure it’s callable, then called with any potential error raised by the HTTP server.

The last public interface of the Micro class is the route method. This method takes a callback parameter, checks if it is callable, then calls it by passing the router instance. This is how we give access to the router attached to the current framework instance. Developers can access the full router API bound to the framework instance.

You may be asking yourself 🤔; How are we giving access to the template engine? That’s exactly what we are going to handle next.

In the snippet below, The NodeJS HTTP handler is implemented by the _handleRequest method. It accepts request and response as parameters. We first call the _patchResponse method. Next, we manually dispatch (forward) the request to the router holding all the routes handlers. The router will then decide which handler to call based on what information it finds in the request.
Calling this._pathResponse(reponse) before dispatching is really important. This will dynamically create the template rendering function, attach it to the response object before handing it over to the dispatch method. This dynamic way of enhancing or modifying an object provided by another system at runtime is called Monkey Patching. This is very easy to achieve in dynamic programming languages.

I don’t know about you but, I believe we have covered a lot in this part of the series 💪🏾💪🏾. As it stands, there is no way to check what we have done. This is one of the reasons TDD was invented; to get early feedback.

Assignment: Write unit-test for this first component while stubbing out or mocking other components to verify our work so far. You are restricted to use only these dependencies package.json.

I hope this will get you out of your comfort zone and set you on the way to be a rock star developer! Next time we will explore and implement the router component of our framework. Until then, Happy coding! 👋🏽