Unit 4.1 · Tutorial 1

Node.js & Express Fundamentals

Chapter 10 · Backend Development
~3 hours Intermediate Node.js · Express · Routing · Middleware

Overview

Node.js has revolutionised backend development by bringing JavaScript to the server. This tutorial covers the fundamentals: the event‑loop, setting up a Node.js project, building RESTful APIs with Express, routing, and middleware. You'll build a solid foundation for backend development.

Why this matters: Node.js is the most popular backend runtime for modern web applications. Understanding its architecture and Express is essential for any full‑stack developer.

1. Node.js & the Event Loop

Node.js is a JavaScript runtime built on Chrome's V8 engine. It uses an event‑driven, non‑blocking I/O model.

The Event Loop

The event loop allows Node.js to perform non‑blocking I/O operations despite being single‑threaded. It offloads operations to the system kernel.

  • Phases: Timers, I/O callbacks, idle, poll, check, close callbacks.
  • Microtasks: `process.nextTick()` and `Promise` callbacks run between phases.
  • Blocking vs Non‑blocking: Use asynchronous APIs (callbacks, Promises, async/await).
// Example: Event loop behaviour console.log('1: Start'); setTimeout(() => console.log('2: Timeout'), 0); Promise.resolve().then(() => console.log('3: Promise')); process.nextTick(() => console.log('4: nextTick')); console.log('5: End'); // Output: 1, 5, 4, 3, 2 (nextTick runs before Promise, both before setTimeout)

2. Project Setup & Basics

Initialisation

mkdir my-api cd my-api npm init -y npm install express npm install --save-dev nodemon

Basic Server

// index.js const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello, World!'); }); app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); });
// package.json scripts "scripts": { "start": "node index.js", "dev": "nodemon index.js" }

3. Express.js Fundamentals

Express is a minimal and flexible Node.js web application framework.

  • Routing: `app.get()`, `app.post()`, `app.put()`, `app.delete()`.
  • Middleware: Functions that execute during the request‑response cycle.
  • Request object: `req.params`, `req.query`, `req.body`.
  • Response object: `res.send()`, `res.json()`, `res.status()`, `res.redirect()`.
// Express app with routes app.get('/users', (req, res) => { res.json([{ id: 1, name: 'Alice' }]); }); app.post('/users', (req, res) => { // req.body contains the parsed JSON const user = req.body; res.status(201).json({ id: 2, ...user }); }); app.get('/users/:id', (req, res) => { const userId = req.params.id; res.json({ id: userId, name: 'User' }); }); app.put('/users/:id', (req, res) => { const userId = req.params.id; const updatedData = req.body; res.json({ id: userId, ...updatedData }); });

4. Routing & Request Handling

Express routing maps HTTP methods and paths to handler functions.

Route parameters

// Route parameters app.get('/products/:category/:id', (req, res) => { const { category, id } = req.params; res.json({ category, id }); });

Query parameters

// Query parameters (e.g., /search?q=node&page=2) app.get('/search', (req, res) => { const { q, page } = req.query; res.json({ query: q, page: page || 1 }); });

Request body parsing

// Add this before your routes app.use(express.json()); // parse application/json app.use(express.urlencoded({ extended: true })); // parse form data

5. Middleware

Middleware functions have access to the request and response objects and the `next()` function.

  • Application‑level: `app.use()` for all routes.
  • Router‑level: `router.use()` for specific routes.
  • Error‑handling: `(err, req, res, next)`.
  • Built‑in: `express.json()`, `express.static()`.
// Logging middleware app.use((req, res, next) => { console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`); next(); // Pass control to the next middleware }); // Authentication middleware const authenticate = (req, res, next) => { const token = req.headers.authorization; if (!token) { return res.status(401).json({ error: 'Unauthorized' }); } // Verify token logic... req.user = { id: 1, name: 'Alice' }; next(); }; // Use authentication middleware on specific routes app.get('/protected', authenticate, (req, res) => { res.json({ user: req.user }); });
// Static files middleware app.use('/static', express.static('public'));

Quiz

Question 1

What is the event loop in Node.js?

  • A loop that runs on the main thread to handle I/O operations
  • A loop that runs on a separate thread for CPU‑intensive tasks
  • A loop that manages database connections
  • A loop that compiles JavaScript code
Show answer
A. A loop that runs on the main thread to handle I/O operations.

Question 2

Which Express method is used to parse JSON request bodies?

  • app.use(express.json())
  • app.use(bodyParser.json())
  • app.use(express.urlencoded())
  • app.json()
Show answer
A. app.use(express.json()).

Question 3

What is the purpose of the `next()` function in Express middleware?

  • To end the response
  • To pass control to the next middleware in the chain
  • To throw an error
  • To redirect the request
Show answer
B. To pass control to the next middleware in the chain.

Exercises

Exercise 1

Create an Express route that handles `GET /greet/:name` and returns a JSON response: `{ message: "Hello, [name]!" }`.

Sample answer
app.get('/greet/:name', (req, res) => { const name = req.params.name; res.json({ message: `Hello, ${name}!` }); });

Exercise 2

Write a middleware that adds a `timestamp` field to every response body. The middleware should add the timestamp after the route handler sends the response.

Sample answer
app.use((req, res, next) => { const originalJson = res.json; res.json = function(data) { data.timestamp = new Date().toISOString(); originalJson.call(this, data); }; next(); });

Homework

Homework 1

Create a simple CRUD API for a "Product" resource with in‑memory storage (an array). Implement `GET /products`, `GET /products/:id`, `POST /products`, `PUT /products/:id`, and `DELETE /products/:id`.

Sample outline
  • Data: `let products = [{ id: 1, name: 'Laptop', price: 999 }]`
  • GET /products: Return all products.
  • GET /products/:id: Return product by ID or 404.
  • POST /products: Generate new ID and add product.
  • PUT /products/:id: Update product or 404.
  • DELETE /products/:id: Remove product or 404.

Mini‑Project

User Management API

Build a user management API with:

  • In‑memory user storage (id, name, email, age)
  • CRUD endpoints
  • A logging middleware that logs each request
  • A simple validation middleware (e.g., age must be > 0)
  • Error handling for non‑existent users (404)
Sample outline
  • Data: `users = [{ id: 1, name: 'Alice', email: 'alice@ex.com', age: 30 }]`
  • Middleware: Logger (`method, url, timestamp`), Validator (check age).
  • Endpoints: Full CRUD.
  • Error: `res.status(404).json({ error: 'User not found' })`.

Tutorial Summary

You learned the fundamentals of Node.js and Express: the event loop, setting up a project, creating routes, handling requests and responses, and using middleware. You built a solid foundation for backend development.

Key takeaway: Express's middleware pipeline is powerful and flexible. Understanding how it works is key to building maintainable APIs.