Building a Multi-Route HTTP Server in JavaScript

Understanding HTTP Servers

Think of an HTTP server as a restaurant's front desk. Just as a host directs customers to different areas of the restaurant (bar, dining room, patio), an HTTP server directs incoming requests to different parts of your application. Each "route" is like a different section of the restaurant, handling specific types of requests.

In the digital world, when you type "www.weather.com/forecast" in your browser, you're essentially walking up to the weather service's front desk and asking, "Can I see the forecast section?" The server then guides you to the right place.

Setting Up Our Server

Let's build our server step by step. First, we'll need Node.js's built-in 'http' module. Think of this as getting the keys to our restaurant and hiring our staff.


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

// Our "restaurant" configuration
const PORT = 3000;
const HOST = 'localhost';

// Create our server (opening our restaurant)
const server = http.createServer((req, res) => {
    // We'll handle requests here
    // This is like our main host/hostess who will guide visitors
});

// Start listening for customers (requests)
server.listen(PORT, HOST, () => {
    console.log(`Server is now open at http://${HOST}:${PORT}`);
});
                

In this setup, PORT is like our restaurant's address number, and HOST is the street name. Together, they tell visitors exactly where to find us.

Creating Routes

Now, let's create different sections in our restaurant (routes in our server). We'll implement a menu system that handles different types of requests.


const server = http.createServer((req, res) => {
    // Parse the URL (like understanding what the customer is asking for)
    const parsedUrl = url.parse(req.url, true);
    const path = parsedUrl.pathname;
    const method = req.method;

    // Set default headers (like greeting customers with a smile)
    res.setHeader('Content-Type', 'application/json');

    // Our route handler (like our restaurant sections)
    switch(path) {
        case '/':
            handleHome(req, res);
            break;
        case '/menu':
            handleMenu(req, res);
            break;
        case '/order':
            handleOrder(req, res);
            break;
        default:
            handle404(req, res);
    }
});

// Home route (like our welcome area)
function handleHome(req, res) {
    res.writeHead(200);
    res.end(JSON.stringify({
        message: 'Welcome to our server!',
        availableRoutes: ['/menu', '/order']
    }));
}

// Menu route (like our menu display)
function handleMenu(req, res) {
    if (req.method === 'GET') {
        res.writeHead(200);
        res.end(JSON.stringify({
            items: [
                { id: 1, name: 'Item 1' },
                { id: 2, name: 'Item 2' }
            ]
        }));
    } else {
        handleMethodNotAllowed(req, res);
    }
}

// Order route (like taking customer orders)
function handleOrder(req, res) {
    if (req.method === 'POST') {
        let body = '';
        req.on('data', chunk => {
            body += chunk.toString();
        });
        req.on('end', () => {
            const order = JSON.parse(body);
            res.writeHead(201);
            res.end(JSON.stringify({
                message: 'Order received',
                order: order
            }));
        });
    } else {
        handleMethodNotAllowed(req, res);
    }
}

// 404 handler (like helping lost customers)
function handle404(req, res) {
    res.writeHead(404);
    res.end(JSON.stringify({
        error: 'Not Found',
        message: 'The requested route does not exist'
    }));
}

// Method not allowed handler
function handleMethodNotAllowed(req, res) {
    res.writeHead(405);
    res.end(JSON.stringify({
        error: 'Method Not Allowed',
        message: `${req.method} is not allowed for this route`
    }));
}
                

Real-World Applications

This server structure is similar to what you might find in real-world applications:

Adding Advanced Features

In a production environment, you might want to add:


// Middleware for logging (like keeping track of all restaurant visitors)
function logRequest(req) {
    console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
}

// Error handling middleware (like having emergency procedures)
function errorHandler(err, res) {
    console.error(err);
    res.writeHead(500);
    res.end(JSON.stringify({
        error: 'Internal Server Error',
        message: 'Something went wrong'
    }));
}

// Authentication middleware (like checking reservations)
function authenticate(req, res, next) {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        res.writeHead(401);
        res.end(JSON.stringify({
            error: 'Unauthorized',
            message: 'Authentication required'
        }));
        return;
    }
    // Continue with the request
    next();
}
                

Testing Our Server

You can test this server using tools like cURL or Postman. Here are some example commands:


# Get home page
 http://localhost:3000/

# Get menu
 http://localhost:3000/menu

# Place an order
try placing an order with postman
 -X POST -H "Content-Type: application/json" \
     -d '{"item": "Item 1", "quantity": 2}' \
     http://localhost:3000/order
                

Further Topics to Explore

To deepen your understanding of HTTP servers, consider exploring:

Security Considerations

In a production environment, remember to implement: