javascript-today

Creating HTTP Servers

NodeJS was designed for building network applications, especially web servers. The built-in http module makes it easy to create HTTP servers without any external dependencies.

Your First HTTP Server

const http = require('http');

// Create server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!');
});

// Start listening
server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

Save as server.js and run:

node server.js

Visit http://localhost:3000 in your browser!

Understanding the Request/Response Cycle

const http = require('http');

const server = http.createServer((req, res) => {
  // req = incoming request from client
  // res = outgoing response to client
  
  console.log('Method:', req.method);      // GET, POST, etc.
  console.log('URL:', req.url);            // /about, /api/users
  console.log('Headers:', req.headers);    // Request headers
  
  // Send response
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/html');
  res.end('<h1>Welcome!</h1>');
});

server.listen(3000);

Routing (Different Pages)

const http = require('http');

const server = http.createServer((req, res) => {
  const { url, method } = req;
  
  // Set content type
  res.setHeader('Content-Type', 'text/html');
  
  // Route based on URL
  if (url === '/') {
    res.statusCode = 200;
    res.end('<h1>Home Page</h1><a href="/about">About</a>');
  } 
  else if (url === '/about') {
    res.statusCode = 200;
    res.end('<h1>About Page</h1><a href="/">Home</a>');
  } 
  else if (url === '/api/users') {
    res.setHeader('Content-Type', 'application/json');
    res.statusCode = 200;
    res.end(JSON.stringify({ users: ['Alice', 'Bob'] }));
  }
  else {
    res.statusCode = 404;
    res.end('<h1>404 - Page Not Found</h1>');
  }
});

server.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Serving JSON (API)

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/api/products' && req.method === 'GET') {
    const products = [
      { id: 1, name: 'Laptop', price: 999 },
      { id: 2, name: 'Mouse', price: 29 },
      { id: 3, name: 'Keyboard', price: 79 }
    ];
    
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify(products));
  } 
  else {
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Not found' }));
  }
});

server.listen(3000);

Reading Request Body (POST Data)

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/api/users' && req.method === 'POST') {
    let body = '';
    
    // Collect data chunks
    req.on('data', chunk => {
      body += chunk.toString();
    });
    
    // When all data received
    req.on('end', () => {
      try {
        const user = JSON.parse(body);
        console.log('Received user:', user);
        
        res.writeHead(201, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ 
          message: 'User created',
          user 
        }));
      } catch (err) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Invalid JSON' }));
      }
    });
  } 
  else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(3000);

Test with curl:

curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","email":"alice@example.com"}'

Serving Static Files

const http = require('http');
const fs = require('fs').promises;
const path = require('path');

const server = http.createServer(async (req, res) => {
  try {
    // Remove query strings and get clean path
    const filePath = path.join(__dirname, 'public', req.url);
    
    // Read file
    const content = await fs.readFile(filePath);
    
    // Determine content type
    const ext = path.extname(filePath);
    const contentTypes = {
      '.html': 'text/html',
      '.css': 'text/css',
      '.js': 'text/javascript',
      '.json': 'application/json',
      '.png': 'image/png',
      '.jpg': 'image/jpeg'
    };
    
    const contentType = contentTypes[ext] || 'text/plain';
    
    res.writeHead(200, { 'Content-Type': contentType });
    res.end(content);
  } catch (err) {
    if (err.code === 'ENOENT') {
      res.writeHead(404);
      res.end('File not found');
    } else {
      res.writeHead(500);
      res.end('Server error');
    }
  }
});

server.listen(3000);

Project structure:

project/
├── server.js
└── public/
    ├── index.html
    ├── style.css
    └── app.js

URL Parsing

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

const server = http.createServer((req, res) => {
  // Parse URL and query string
  const parsedUrl = url.parse(req.url, true);
  
  console.log('Path:', parsedUrl.pathname);     // /search
  console.log('Query:', parsedUrl.query);       // { q: 'nodejs', page: '2' }
  
  if (parsedUrl.pathname === '/search') {
    const searchTerm = parsedUrl.query.q;
    const page = parsedUrl.query.page || 1;
    
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ 
      search: searchTerm,
      page: page,
      results: []
    }));
  } else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(3000);

Visit: http://localhost:3000/search?q=nodejs&page=2

Headers and Cookies

const http = require('http');

const server = http.createServer((req, res) => {
  // Read request headers
  console.log('User-Agent:', req.headers['user-agent']);
  console.log('Cookie:', req.headers.cookie);
  
  // Set response headers
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Powered-By', 'NodeJS');
  
  // Set cookie
  res.setHeader('Set-Cookie', 'sessionId=abc123; HttpOnly; Max-Age=3600');
  
  // Multiple headers
  res.writeHead(200, {
    'Content-Type': 'application/json',
    'Cache-Control': 'no-cache',
    'Access-Control-Allow-Origin': '*'
  });
  
  res.end(JSON.stringify({ message: 'Headers set' }));
});

server.listen(3000);

Complete REST API Example

const http = require('http');

// In-memory data store
let users = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' }
];
let nextId = 3;

const server = http.createServer((req, res) => {
  const { method, url } = req;
  
  // Helper to send JSON
  const sendJSON = (statusCode, data) => {
    res.writeHead(statusCode, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify(data));
  };
  
  // GET /api/users - List all users
  if (url === '/api/users' && method === 'GET') {
    sendJSON(200, users);
  }
  
  // GET /api/users/:id - Get single user
  else if (url.match(/^\/api\/users\/\d+$/) && method === 'GET') {
    const id = parseInt(url.split('/')[3]);
    const user = users.find(u => u.id === id);
    
    if (user) {
      sendJSON(200, user);
    } else {
      sendJSON(404, { error: 'User not found' });
    }
  }
  
  // POST /api/users - Create user
  else if (url === '/api/users' && method === 'POST') {
    let body = '';
    
    req.on('data', chunk => { body += chunk; });
    req.on('end', () => {
      const newUser = JSON.parse(body);
      newUser.id = nextId++;
      users.push(newUser);
      sendJSON(201, newUser);
    });
  }
  
  // PUT /api/users/:id - Update user
  else if (url.match(/^\/api\/users\/\d+$/) && method === 'PUT') {
    const id = parseInt(url.split('/')[3]);
    let body = '';
    
    req.on('data', chunk => { body += chunk; });
    req.on('end', () => {
      const updates = JSON.parse(body);
      const index = users.findIndex(u => u.id === id);
      
      if (index !== -1) {
        users[index] = { ...users[index], ...updates };
        sendJSON(200, users[index]);
      } else {
        sendJSON(404, { error: 'User not found' });
      }
    });
  }
  
  // DELETE /api/users/:id - Delete user
  else if (url.match(/^\/api\/users\/\d+$/) && method === 'DELETE') {
    const id = parseInt(url.split('/')[3]);
    const index = users.findIndex(u => u.id === id);
    
    if (index !== -1) {
      users.splice(index, 1);
      sendJSON(200, { message: 'User deleted' });
    } else {
      sendJSON(404, { error: 'User not found' });
    }
  }
  
  // Not found
  else {
    sendJSON(404, { error: 'Endpoint not found' });
  }
});

server.listen(3000, () => {
  console.log('API server running on http://localhost:3000');
  console.log('Try: GET http://localhost:3000/api/users');
});

Test the API:

# Get all users
curl http://localhost:3000/api/users

# Get single user
curl http://localhost:3000/api/users/1

# Create user
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Charlie","email":"charlie@example.com"}'

# Update user
curl -X PUT http://localhost:3000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice Updated"}'

# Delete user
curl -X DELETE http://localhost:3000/api/users/2

Why Use Express?

The raw http module works but is verbose. Compare:

Raw HTTP:

const server = http.createServer((req, res) => {
  if (req.url === '/api/users' && req.method === 'GET') {
    // ... 10 lines of code
  }
});

Express:

const app = express();
app.get('/api/users', (req, res) => {
  res.json(users);
});

Express provides:

  • Simpler routing
  • Middleware support
  • Request parsing built-in
  • Template engines
  • Static file serving

Summary

Concept Code
Create server http.createServer((req, res) => {})
Start server server.listen(3000)
Send text res.end('Hello')
Send JSON res.end(JSON.stringify(data))
Set status res.statusCode = 404
Set header res.setHeader('Content-Type', 'text/html')
Read body req.on('data', chunk => {})
Parse URL url.parse(req.url, true)