Intro to Backend Development with Node.js

Workshop

OpenMinds Club Logo
openmindsclub.net

Aymen Ghemam/@token

What is Backend Development?

  • The "server-side" of web applications.
  • Handles logic users don't directly see.

Backend Responsibilities (1/2)

  • Storing and organizing data (databases).
  • Processing user requests.
  • Handling application logic & business rules.

Backend Responsibilities (2/2)

  • Authentication and security.
  • Communicating with other services (APIs).
  • Think of it as the "engine" & "kitchen".

The Web vs. The Internet

  • Internet: Global network infrastructure (hardware, TCP/IP).
  • Web (WWW): Information system *on top* of the Internet (HTTP, Browsers, Servers).

Client vs Server: Definitions

  • Client: Requests resources (Browser, App).
  • Server: Stores resources, processes requests.

Client vs Server: Communication

The Request-Response Cycle

  • Client sends HTTP Request.
  • Server processes request.
  • Server sends HTTP Response back.

What is an API?

Application Programming Interface

  • Rules & tools for software interaction.
  • Defines how components talk to each other.
  • Analogy: A restaurant menu (defines orders/results).

Why Use APIs?

  • Contract: Clear expectations for interaction.
  • Abstraction/Decoupling: Hides internal complexity (frontend independent of backend internals).
  • Reusability: Single API serves multiple clients (web, mobile).

API Example

GET Request for User Data


// Request: Get user with ID 123
// Method: GET
// Endpoint: /users/42

// Server Response (JSON):
{
  "id": 42,
  "name": "Tux",
  "email": "tux@openmindsclub.com"
}
              

Common HTTP Methods

CRUD Operations

  • GET: Read data (Read)
  • POST: Create data (Create)
  • PUT: Update/Replace data (Update)
  • PATCH: Partially update data (Update)
  • DELETE: Remove data (Delete)

Introduction to Node.js Node.js Logo Placeholder

  • JavaScript Runtime Environment.
  • Runs JS code *outside* the browser (server-side).
  • Built on Chrome's V8 engine.

Node.js Key Features

  • Javascript
  • Non-blocking I/O
  • Event-driven architecture

(We'll explain these next!)

Non-blocking vs Blocking

Waiter Analogy

  • Blocking: Waiter takes order, waits for food, serves, *then* takes next order. (Slow!)
  • Non-blocking (Node.js): Waiter takes order, gives to kitchen, immediately takes next order. (Doesn't wait idly!)

Event-Driven Architecture

Handling Completed Tasks

  • When kitchen finishes food (I/O operation completes), it signals (emits event).
  • Waiter (Event Loop) notices signal, serves food (executes callback).
  • Result: Handles many requests efficiently with one thread.

Node.js Event Loop Diagram

(Hada very simplified view)

Diagram Placeholder: Simplified Node.js Event Loop

Common Node.js Use Cases (1/2)

  • Web Servers & APIs: Efficient I/O, JS everywhere.
  • Real-time Applications: Chats, live updates (event-driven).
  • Microservices: Small, independent services.
  • Command Line (CLI) Tools: Automation, build scripts.

Common Node.js Use Cases (2/2)

  • Data Streaming: Efficiently handling large data flows.
  • SPA Backends: Data source for React/Vue/Angular.

What is npm?

Node Package Manager

  • Installed with Node.js.
  • Functions:
    • Package Repository (Libraries/Modules).
    • Command Line Tool (Manage project).

npm: `package.json` File (1/2)

Project Configuration

  • Key project file.
  • Contains Metadata (name, version).

npm: `package.json` File (2/2)

Dependencies and Scripts

  • Lists `dependencies` (needed to run).
  • Lists `devDependencies` (needed for dev).
  • Defines `scripts` (shortcuts for tasks).

npm: Common Commands (1/2)

  • npm init -y: Create `package.json`.
  • npm install <pkg>: Install runtime dependency.
  • npm install <pkg> --save-dev: Install dev dependency.

npm: Common Commands (2/2)

  • npm install: Install all dependencies from `package.json`.
  • npm run <script_name>: Execute a script.
  • npx <command>: Execute package command without global install.

Setting Up: Install & Verify

  • 1. Install Node.js: Get LTS from nodejs.org.
  • 2. Verify (Terminal):
    node -v
    npm -v

Setting Up: Initialize Project

  • 3. Create & Navigate:
    mkdir my-node-app
    cd my-node-app
  • 4. Initialize npm:
    npm init -y
    (Creates `package.json`)

Setting Up: Dev Tip

Auto-Restart Server

  • Use `nodemon` for development.
  • It restarts your app automatically on file changes.
  • Run with: `npx nodemon your_script.js`

Modules in Node.js

Organizing code into reusable pieces.

Two main systems...

Module System: CommonJS (1/2)

The Original

  • Uses require() to import.
  • Uses module.exports / exports to export.

Module System: CommonJS (2/2)

Characteristics

  • Typically .js files.
  • Loads Synchronously.
  • Still very common.

Module System: ES Modules (1/2)

The Standard

  • Uses import to import.
  • Uses export to export.

Module System: ES Modules (2/2)

Characteristics & Usage

  • Typically .js or .mjs files.
  • Loads Asynchronously.
  • Enable with "type": "module" in `package.json` or use .mjs extension.

CommonJS Example


// hello.js
const generateGreeting = name => `Hi, ${name}!`;
module.exports = generateGreeting;

// --- app.js ---
const greet = require('./greet.js');
console.log(greet('OMC')); // Hi, OMC!
              

ES Modules Example

(Needs setup: `type: "module"` or `.mjs`)


// hello.mjs
export const generateGreeting = name => `Hi, ${name}!`;

// --- app.mjs ---
import { generateGreeting } from './greet.mjs';
console.log(generateGreeting('OMC')); // Hi, OMC!
              

Core Modules

Built-in Node.js functionality (no install needed).

Core Modules: File & Path

  • fs (File System): Read/write files.
  • path:** Work with file/directory paths cross-platform.

Core Modules: Networking

  • http:** Create HTTP servers / clients.
  • https:** Create secure HTTPS servers / clients.

Core Modules: URL & OS

  • url:** Parse URL strings.
  • os (Operating System): Get OS info (CPU, memory).

Core Modules: Events

  • events:** Create custom event emitters/listeners (key to Node's async nature).

See Node.js docs for many more!

Core Module Example: `fs` Code

Writing a file synchronously


const fs = require('fs');

const filePath = 'hello.txt';
const fileContent = 'Hello from Node.js! 👋';

try {
  fs.writeFileSync(filePath, fileContent); // Sync!
  console.log(`Wrote to ${filePath}`);
} catch (err) {
  console.error('Error writing file:', err);
}
              

Core Module Example: `fs` Explanation

  • Imports `fs` module (CommonJS style).
  • `writeFileSync` writes the file *synchronously*.
  • Synchronous operations block the Event Loop!
  • **Caution:** Avoid sync I/O in servers; use async versions like `fs.writeFile()` or `fs.promises.writeFile()`.

Creating a Basic HTTP Server

Using the built-in `http` module.

HTTP Server Code (1/2)


// 1. Import the core 'http' module
const http = require('http');

// 2. Define hostname and port
const hostname = '127.0.0.1'; // localhost
const port = 3000;

// 3. Create the server with a request listener
const server = http.createServer((req, res) => {
  // ... listener code on next slide ...
              

HTTP Server Code (2/2)


// ... (inside http.createServer callback) ...
  console.log(`Req: ${req.method} ${req.url}`);

  // 4. Set response status and headers
  res.statusCode = 200; // OK
  res.setHeader('Content-Type', 'text/plain');

  // 5. Write response body and end
  res.end('Hello from Node.js Server!\n');
}); // End of createServer callback

// 6. Start listening
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
               

HTTP Server Explanation (1/2)

  1. Import `http`.
  2. Define `hostname` and `port`.
  3. `http.createServer(callback)`: Creates server. Callback (`request listener`) runs for *every* request. Gets `req` (request) & `res` (response) objects.

HTTP Server Explanation (2/2)

  1. Set `res.statusCode` and headers (`res.setHeader`).
  2. Send response body and finish with `res.end()`.
  3. `server.listen()` starts the server. Callback runs once listening begins.

Run: `node server.js`, Visit: `http://127.0.0.1:3000`

Middleware

Functions processing requests in a chain.

Middleware Concept (1/2)

Definition & Access

  • Sit *between* request & final handler.
  • Functions with access to:
    • Request object (`req`)
    • Response object (`res`)
    • `next()` function (pass control)

Middleware Concept (2/2)

Common Uses

  • Logging requests
  • Parsing request bodies (JSON, form data)
  • Authentication / Authorization
  • Adding CORS headers
  • Data validation

Middleware: The Chain & `next()`

How it Works

  • Think of an assembly line / chain.
  • Each middleware does its job.
  • Calls next() to pass request to the next middleware or handler.
  • Crucial: If `next()` isn't called, the request stops!

Middleware Example: Code

Simple Request Logger


const logger = (req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] ${req.method} ${req.url}`);

  next(); // Pass control!
};

// Usage is simpler with frameworks like Express:
// app.use(logger);
              

Middleware Example: Explanation

  • Logs timestamp, method, URL.
  • Calls `next()` to allow request processing to continue.
  • If `next()` was missing, requests using this middleware would hang.

Beyond Core Modules: Frameworks

Why use them?

Why Frameworks? (1/2)

Limitations of Core `http`

  • Core `http` is very low-level.
  • You'd manually handle:
    • Routing (URLs, methods)
    • Request body parsing
    • Middleware flow
    • Consistent responses

Why Frameworks? (2/2)

Boilerplate & Structure

  • Frameworks reduce repetitive boilerplate code.
  • Provide structure and helpers for common tasks.
  • Lead to faster, more robust development.

Framework Benefits (1/3)

  • Routing: Easily map paths/methods to handlers (e.g., `app.get('/users', ...)`)
  • Middleware Management: Simple way to apply middleware globally or per-route (`app.use(...)`).

Framework Benefits (2/3)

  • Request/Response Helpers: Easy access to params, query, body (`req.params`, `req.body`). Simple responses (`res.json()`, `res.send()`, `res.status()`).

Framework Benefits (3/3)

  • Template Engines: Integration for server-side HTML rendering.
  • Error Handling: Centralized ways to manage errors.

Popular Node.js Frameworks

  • Express.js: Minimalist, flexible, most popular.
  • Koa.js: Modern, uses async/await heavily.
  • Fastify: Focus on speed & low overhead.
  • NestJS: Opinionated, TypeScript-based, modular (like Angular).

Express.js Example: Code (1/2)

Setup and Root Route


// 1. Install: npm install express
const express = require('express');
const app = express(); // Create app
const port = 3000;

// 4. Root route handler (GET '/')
app.get('/', (req, res) => {
  res.send('Hello World from Express!');
});
              

Express.js Example: Code (2/2)

API Route and Server Start


// Example API route
app.get('/api/greet', (req, res) => {
  res.json({ message: 'Hello from API!' });
});

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

Express.js Example: Explanation

  • Requires `express` after installing.
  • Creates an `app` instance.
  • Uses `app.METHOD(PATH, HANDLER)` for routing (e.g., `app.get`).
  • Uses helper methods like `res.send()` and `res.json()`.
  • Much cleaner than raw `http` for routing!

Questions?