← Back to Tutorials Chapter 6

Building Applications with Node.js

Frameworks Overview

While Node.js core provides the HTTP module, frameworks simplify building web applications:

Express.js

Express is the de facto standard web framework for Node.js. It provides a robust set of features for web and mobile applications.

// Install: npm install express

const express = require('express');
const app = express();
const port = 3000;

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.get('/', (req, res) => {
  res.send('Hello, Express!');
});

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
});

app.post('/api/users', (req, res) => {
  const user = req.body;
  res.status(201).json({ message: 'User created', user });
});

app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
});

Middleware

Middleware functions are the building blocks of Express applications. They have access to the request object, response object, and the next function.

// Custom middleware
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
  next();
};

const authenticate = (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  req.user = { id: 1, name: 'Alice' }; // Simplified
  next();
};

// Apply middleware
app.use(logger);
app.use('/api/protected', authenticate);

// Route-level middleware
const validateUser = (req, res, next) => {
  if (!req.body.name) {
    return res.status(400).json({ error: 'Name is required' });
  }
  next();
};

app.post('/api/users', validateUser, (req, res) => {
  res.json({ success: true });
});

REST API Design

MethodRouteAction
GET/api/tasksList all tasks
GET/api/tasks/:idGet a single task
POST/api/tasksCreate a task
PUT/api/tasks/:idUpdate a task
DELETE/api/tasks/:idDelete a task

Authentication

// Install: npm install jsonwebtoken bcrypt

const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

const SECRET = process.env.JWT_SECRET || 'fallback-secret';

// Hash password
async function hashPassword(password) {
  const salt = await bcrypt.genSalt(10);
  return bcrypt.hash(password, salt);
}

// Generate JWT
function generateToken(user) {
  return jwt.sign({ id: user.id, email: user.email }, SECRET, {
    expiresIn: '7d'
  });
}

// Verify JWT middleware
function verifyToken(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'Access denied' });

  try {
    const decoded = jwt.verify(token, SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(403).json({ error: 'Invalid token' });
  }
}

Integrating with Frontend

Serve static files and enable CORS for your frontend application:

// Serve static files
app.use(express.static('public'));

// Enable CORS (Install: npm install cors)
const cors = require('cors');
app.use(cors({ origin: 'http://localhost:5173' }));

// Fallback for SPA routing
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
Exercise: Build a simple task management REST API using Express.js with the following endpoints: GET /tasks, POST /tasks, PUT /tasks/:id, DELETE /tasks/:id. Use an in-memory array as storage and add basic request validation.