The NodeJS ecosystem is full of libraries and frameworks that help us perform common tasks such as creating route handlers. However, we can do all of these high-level things without using any other external tools. In this post, we will learn how to implement NodeJS Routing without Express.

Of course, in a real production application, we will always be using some framework such as Express, NestJS, KoaJS or Fastify. But it is still good to know how things work without these abstractions.

If you are totally new to NodeJS, I will recommend you start with the post about creating a NodeJS server.

1 – NodeJS Routing without Express

To demonstrate our target of implementing NodeJS routing without using Express framework or any other framework, let us visualize a simple application requirement.

Our application will have a root path that will display a small form with a single text field. When user enters some value in the text field, we will submit the form, redirect to a different URL and save the contents of the text field into a file.

In the first step, we will handle the root path. See below code snippet.

const http = require('http');

function reqListener(req, res) {
    const url = req.url;

    if (url === '/') {
        res.write('<html>');
        res.write('<head><title>Enter</title></head>')
        res.write('<body><form action="/message" method="POST"><input type="text" name="message"><button type="submit">Send</button></form></body>')
        res.write('</html');
        return res.end();
    }
}

const server = http.createServer(reqListener)

server.listen(3000);

As you can see, we get access to the http module. We use the http module to call createServer() method. Basically, this method accepts a function with the NodeJS request response objects. This function is the request listener and NodeJS will call this function for every incoming request.

We also implement the request listener function where we extract the req.url value from the request object. If the url is equal to / (or the root path), we write some HTML to the response object using res.write().

The HTML code is nothing but our small form with a single text input field. We set the form action to redirect to /message and also, we set the method type as POST.

Note that we call res.end() to tell NodeJS that we are done writing the response.

With this, we are done with the first part of our application. However, now we need to write the logic to handle the incoming request from the input form.

2 – NodeJS Handling Request Body without Express

Let us now implement the handler for the /message route.

See below code that has been enhanced for the same.

const http = require('http');
const fs = require('fs');

function reqListener(req, res) {
    const url = req.url;
    const method = req.method;

    if (url === '/') {
        res.write('<html>');
        res.write('<head><title>Enter</title></head>')
        res.write('<body><form action="/message" method="POST"><input type="text" name="message"><button type="submit">Send</button></form></body>')
        res.write('</html');
        return res.end();
    }

    if (url === '/message' && method === 'POST') {
        const body = [];
        req.on('data', (chunk) => {
            console.log(chunk);
            body.push(chunk);
        })

        req.on('end', () => {
            const parsedBody = Buffer.concat(body).toString();
            const message = parsedBody.split('=')[1];
            fs.writeFile('message.txt', message, (err) => {
                res.statusCode = 302;
                res.setHeader('Location', '/');
                return res.end();
            });
        });
    }

}

const server = http.createServer(reqListener)

server.listen(3000);

As you can see, we import the fs module as well. This is a NodeJS core module to deal with file system.

Then, we also extract the req.method property from the request object. We need this to make sure that our form submit request is a POST request.

Next, we implement another condition in which we check if the path is equal to /message and method is POST. If the condition is true, we register a couple of listeners on the request object.

The first listener is for the data event. Basically, the request is received in the form of a continuing stream of data. Within the stream, we get chunks of data. Within the data event listener, we have a callback that takes these chunks and pushes them into an array named body.

Next, we have the listener for the request end event. Basically, this is triggered when the entire request data has been streamed to our application. At this point, we can be sure that the body array contains the complete request. Think of it as a bus reaching its final stop and all the passengers are now present. At this point, we use the Buffer.concat() method to combine the entire data and convert it to string.

The data is in the form of key value pair. So it will be something like message=test because our form field had the name message. However, we are only interested in the value of the message and hence, we use split to extract the same from the parsedBody constant.

Finally, we use the fs.writeFile() method to write the message to the message.txt file. Within the callback to the writeFile() method, we set the response object along with status code of 302 (redirect). We also set the location back to the root path and call res.end().

We can now run our application using the command node app.js and test our functionality.

Conclusion

With this, we have successfully implemented NodeJS routing without Express framework. We handled path as well as HTTP method in our routing logic.

Want to learn more NodeJS use-cases? Check out this post on NodeJS Pipeline using Redis.

If you have any comments or queries about this post, please feel free to mention them in the comments section below.

Categories: BlogNodeJS

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

4 Comments

Mihir L. Agrawal · October 20, 2022 at 2:38 pm

Hey thanks for writing this. Sometimes in the world of shinny frameworks we forget how things work behind the scenes.
Would love to read more of this content and would like to connect with you sir on linked in;
linkedin.com/in/mihir-l-agrawal

    Saurabh Dashora · October 29, 2022 at 1:31 pm

    Hi Mihir,

    Thanks for the great feedback! Do subscribe to the newsletter for regular posts.

Theo · August 16, 2023 at 2:08 am

This was really helpful. Just what I was looking for. Thank you.

I noticed on your About page (https://progressivecoder.com/about/) that your contact form is not showing correctly. It is displaying the WP shortcode rather than the form.

Cheers.

    Saurabh Dashora · August 20, 2023 at 2:05 am

    Thanks for the feedback Theo!

Leave a Reply

Your email address will not be published. Required fields are marked *