Basic Web Server Routing
# Creating a Basic Web Server
Welcome to Chapter 10! In the previous chapter, we built a server that responded to every single request with the exact same message. But real websites have multiple pages—a home page, an about page, a contact page.
How do we tell our server to send different data depending on where the user clicked? The answer is Routing, and we will learn how to build a router from scratch in this chapter.
---
1. Introduction
Routing is the process of determining what the server should do based on the client's request. It relies primarily on two things:
-
1.
The URL Path: (
/about,/contact,/users)
-
2.
The HTTP Method: (
GET,POST,PUT,DELETE)
Right now, we will focus solely on GET requests (which is what happens when you type a URL into a browser and hit enter). By inspecting the req.url property, we can use simple if/else logic to serve different HTML files to the user.
---
2. Learning Objectives
By the end of this chapter, you will be able to:
- Understand the concept of backend routing.
-
Inspect
req.urlto serve different responses.
-
Combine the
http,fs, andpathmodules to serve physical HTML files.
- Handle 404 errors when a user visits a route that doesn't exist.
- Build a multi-page personal website server.
---
3. Beginner-Friendly Explanations
What is a Route?
Imagine a receptionist at a large office building.-
Visitor: "I need the Sales department." (URL:
/sales)
- Receptionist (Router): "Take the elevator to the 2nd floor."
-
Visitor: "I need the HR department." (URL:
/hr)
- Receptionist (Router): "Take the elevator to the 5th floor."
If the visitor asks for the "Magic department" (/magic), the receptionist says, "Sorry, that doesn't exist here" (A 404 Not Found error).
In our Node.js server, the callback function inside createServer acts as the receptionist.
---
4. Syntax Explanation
Let's look at how to build a basic router using an if/else block.
```javascript id="ch10-syntax-1" const http = require('http');
const server = http.createServer((req, res) => { // 1. Inspect the requested URL const url = req.url;
// 2. Route the request if (url === '/') { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<h1>Home Page</h1>'); } else if (url === '/about') { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<h1>About Us</h1>'); } else { // 3. Handle 404 Not Found res.writeHead(404, {'Content-Type': 'text/html'}); res.end('<h1>404 - Page Not Found!</h1>'); } });
server.listen(3000);
html id="ch10-html-1" <!-- index.html --> <html><body><h1>Welcome to the Home Page</h1></body></html>
html id="ch10-html-2" <!-- about.html --> <html><body><h1>About Our Company</h1></body></html>
javascript id="ch10-code-1" const http = require('http'); const fs = require('fs'); const path = require('path');
const server = http.createServer((req, res) => { if (req.url === '/') { // BAD: Blocks the thread while reading const html = fs.readFileSync(path.join(__dirname, 'index.html')); res.writeHead(200, {'Content-Type': 'text/html'}); res.end(html); } });
javascript id="ch10-code-2" const http = require('http'); const fs = require('fs'); const path = require('path');
const server = http.createServer((req, res) => { if (req.url === '/') { const filePath = path.join(__dirname, 'index.html'); // GOOD: Reads the file asynchronously fs.readFile(filePath, (err, content) => { if (err) { res.writeHead(500); // 500 means Server Error res.end("Error loading the page"); } else { res.writeHead(200, {'Content-Type': 'text/html'}); res.end(content); } }); } });
javascript id="ch10-mini-project" // portfolio.js const http = require('http'); const fs = require('fs'); const path = require('path');
// Helper function to serve files function serveFile(res, fileName, statusCode = 200) { const filePath = path.join(__dirname, 'public', fileName); fs.readFile(filePath, (err, content) => { if (err) { res.writeHead(500, {'Content-Type': 'text/plain'}); res.end("500 - Internal Server Error"); return; } res.writeHead(statusCode, {'Content-Type': 'text/html'}); res.end(content); }); }
const server = http.createServer((req, res) => {
console.log(Requested: ${req.url});
switch(req.url) { case '/': case '/home': serveFile(res, 'home.html'); break; case '/projects': serveFile(res, 'projects.html'); break; default: // Send the 404 page and a 404 status code serveFile(res, '404.html', 404); break; } });
server.listen(3000, () => {
console.log("Portfolio server running on http://localhost:3000");
});
``
Run it:
node portfolio.js
---
12. Coding Challenges
Challenge 1: Create an API route. If req.url === '/api/user', set the content-type to 'application/json' and res.end() a stringified JSON object containing your name and email.
Challenge 2: Currently, our server can only handle .html files. Research how to dynamically change the Content-Type so you can serve .css and .png files as well.
---
13. MCQs with Answers
Q1: In Node.js routing, which property tells you what path the user is trying to access?
A) req.path
B) req.url
C) res.url
D) req.route
Answer: B
Q2: Which HTTP status code should you send if a route does not exist? A) 200 B) 400 C) 404 D) 500 Answer: C
Q3: Which module is required to read an HTML file from the hard drive so it can be sent to the client?
A) http
B) html
C) path
D) fs
Answer: D
Q4: If a user visits http://localhost:3000/, what is the value of req.url?
A) localhost
B) 3000
C) /
D) null
Answer: C
---
14. Interview Questions
- 1. What is routing in the context of a web server?
-
2.
Why is using fs.readFileSync
a bad idea in a web server router?
.
---
15. FAQs
Q: Writing routes with
if/else seems tedious. Is there a better way?
A: Yes! As an application grows, doing this manually with the raw http module becomes a nightmare. That is exactly why the Express.js framework was created. We are doing it the hard way now so you understand the magic behind Express later!
Q: Can I serve images using this method?
A: Yes, but you have to use
fs.readFile without 'utf8' so it reads the image as a binary Buffer, and you must set the header to {'Content-Type': 'image/jpeg'}.
---
16. Summary
-
Routing directs traffic based on the
req.url.
-
The root page of a website is always
/.
-
Use
fs.readFile combined with path.join` to safely read HTML files.
- Always send a 404 status code for unhandled routes.
- Helper functions make routing much cleaner and prevent repetitive code.
---
17. Next Chapter Recommendation
We have successfully built a server using only built-in Core modules! But developers don't like reinventing the wheel. There are thousands of pre-built modules on the internet we can download to make our lives easier. In Chapter 11: Understanding NPM, we will learn how to download open-source code to supercharge our applications!