Intro to Backend Development with Node.js
Workshop
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
- 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)
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
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)
- Import `http`.
- Define `hostname` and `port`.
-
`http.createServer(callback)`: Creates server. Callback (`request
listener`) runs for *every* request. Gets `req` (request) & `res`
(response) objects.
HTTP Server Explanation (2/2)
- Set `res.statusCode` and headers (`res.setHeader`).
- Send response body and finish with `res.end()`.
-
`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!