C4 Skilling.
© SKILLING | REFCARD | APRIL 2026
CONTENTS
G E T T I N G S TA R T E D W I T H
Full Stack: [Link]
— Introduction To [Link]
Runtime And Event-driven
Architecture
Runtime & Event
— The [Link] Event Loop In
Depth
— Asynchronous Patterns In
Loop, [Link]
[Link]
— [Link] Fundamentals
And Application Structure
Routing & Middleware
— [Link] Routing In Depth
— [Link] Middleware Deep
Dive
— Conclusion
A Beginner-Friendly Reference Guide for Developers
A Skilling Refcard provides concise
reference guides on key
technology topics for practitioners.
WRITTEN BY
KMIT FS Team
REFCARD
RC-C4-FSD-2026
© SKILLING | REFCARD | APRIL 2026 1
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
I N T R O D U C T I O N TO N O D E . J S R U N T I M E A N D E V E N T- D R I V E N A R C H I T E C T U R E
[Link] revolutionized server-side development by bringing JavaScript to the backend. Understanding how [Link] executes code through its runtime and event-
driven architecture is fundamental to building efficient, scalable applications.
This section covers the core concepts that make [Link] unique: its single-threaded nature, non-blocking I/O model, and the powerful event loop that orchestrates
asynchronous operations.
[Link] Architecture Overview
WHAT IS [Link] RUNTIME
The [Link] runtime is an execution environment that allows JavaScript to run outside the browser. It combines the V8 JavaScript engine (developed by Google for
Chrome) with libuv, a cross-platform library handling asynchronous I/O operations.
Key characteristics:
Single-threaded execution for JavaScript code
Non-blocking I/O operations delegated to the system
Cross-platform compatibility (Windows, macOS, Linux)
Built-in modules for file system, networking, and more
Unlike traditional server environments that spawn new threads per request, [Link] handles thousands of concurrent connections efficiently using its event-driven
model.
JAVASCRIPT Verifying [Link] Runtime Information
// Check [Link] version and runtime details
[Link]('[Link] Version:', [Link]);
[Link]('Platform:', [Link]);
[Link]('Architecture:', [Link]);
[Link]('Process ID:', [Link]);
// Memory usage information
const memUsage = [Link]();
[Link]('Heap Used:', [Link]([Link] / 1024 / 1024), 'MB');
[Link]('Heap Total:', [Link]([Link] / 1024 / 1024), 'MB');
V8 ENGINE AND JAVASCRIPT COMPILATION
The V8 engine compiles JavaScript directly to native machine code using Just-In-Time (JIT) compilation, making [Link] extremely fast. V8 performs several
optimizations:
1. Parsing - Converts JS source to Abstract Syntax Tree (AST)
2. Ignition - Interprets and generates bytecode
3. TurboFan - Optimizes hot code paths to machine code
4. Garbage Collection - Automatic memory management
V8's optimization strategies include:
Inline caching for property access
Hidden classes for object shape optimization
© SKILLING | REFCARD | APRIL 2026 2
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
Dead code elimination removing unused branches
V8 Compilation Pipeline
LIBUV AND CROSS-PLATFORM ABSTRACTION
libuv is the C library that provides [Link] with its asynchronous I/O capabilities. It abstracts operating system differences, ensuring consistent behavior across
platforms.
libuv provides:
Event loop implementation
Thread pool (default 4 threads) for blocking operations
Async TCP/UDP sockets
File system operations
Child process management
Signal handling
Operations handled by the thread pool:
File system operations ( [Link] , [Link] )
DNS lookups ( [Link] )
Cryptographic operations ( crypto.pbkdf2 )
Compression ( zlib )
JAVASCRIPT Configuring libuv Thread Pool Size
// Set thread pool size BEFORE requiring any modules
// Default is 4, maximum is 1024
[Link].UV_THREADPOOL_SIZE = 8;
const crypto = require('crypto');
const fs = require('fs');
// These operations use the thread pool
const start = [Link]();
// Simulate CPU-intensive crypto operations
for (let i = 0; i < 4; i++) {
crypto.pbkdf2('password', 'salt', 100000, 512, 'sha512', () => {
[Link](`Hash ${i + 1} completed in ${[Link]() - start}ms`);
});
}
T H E N O D E . J S E V E N T LO O P I N D E P T H
The event loop is the heart of [Link]'s asynchronous programming model. It continuously monitors the call stack and callback queues, executing callbacks when
the stack is empty.
Understanding the event loop phases helps you write predictable asynchronous code and avoid common pitfalls like blocking the main thread.
© SKILLING | REFCARD | APRIL 2026 3
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
Event Loop Phases Diagram
Event Loop Phases and Their Responsibilities
PHASE QUEUE TYPE CALLBACKS EXECUTED EXAMPLE APIS
Timers Min-Heap setTimeout, setInterval callbacks setTimeout(), setInterval()
Pending Callbacks FIFO Queue Deferred I/O callbacks TCP errors, some OS callbacks
Poll FIFO Queue I/O callbacks (except close/timers/check) [Link](), network I/O
Check FIFO Queue setImmediate callbacks setImmediate()
Close Callbacks FIFO Queue Close event callbacks [Link]('close')
Microtasks FIFO Queue Promise callbacks, queueMicrotask [Link](), async/await
JAVASCRIPT Demonstrating Event Loop Phase Order
const fs = require('fs');
// Timers phase
setTimeout(() => [Link]('1. setTimeout'), 0);
// Check phase
setImmediate(() => [Link]('2. setImmediate'));
// Microtask queue (runs between phases)
[Link]().then(() => [Link]('3. [Link]'));
// nextTick queue (highest priority microtask)
[Link](() => [Link]('4. [Link]'));
// Synchronous code runs first
[Link]('5. Synchronous');
// Output order:
// 5. Synchronous
// 4. [Link]
// 3. [Link]
// 1. setTimeout (or 2, order varies outside I/O)
// 2. setImmediate (or 1)
TIMERS PHASE
The timers phase executes callbacks scheduled by setTimeout() and setInterval() . [Link] uses a min-heap data structure to efficiently track timer
expiration.
Important characteristics:
Timer thresholds are minimum delays, not guaranteed exact times
© SKILLING | REFCARD | APRIL 2026 4
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
The event loop may delay execution if previous phases take longer
setTimeout(fn, 0) doesn't mean immediate execution—it means "as soon as possible after current operations"
Technical detail: [Link] coalesces timers with the same expiration time, executing them in the order they were registered.
JAVASCRIPT Timer Behavior and Delays
const start = [Link]();
// Schedule timer for 100ms
setTimeout(() => {
const delay = [Link]() - start;
[Link](`Timer fired after ${delay}ms (requested 100ms)`);
}, 100);
// Blocking operation delays the timer
const blockFor = 200; // milliseconds
while ([Link]() - start < blockFor) {
// Blocking the event loop
}
[Link]('Blocking complete');
// Output: Timer fires after ~200ms, not 100ms
POLL PHASE AND I/O HANDLING
The poll phase is where [Link] spends most of its time. It retrieves new I/O events from the operating system and executes their callbacks.
Poll phase behavior:
1. Calculate timeout - How long to block for I/O
2. Process events - Execute callbacks in the poll queue
3. Check for timers - If timers are due, loop back to timers phase
The poll phase will:
Block and wait for I/O if the queue is empty and no timers are scheduled
Process all callbacks in the queue before moving on
Yield to check phase if setImmediate() callbacks are pending
Poll Phase Decision Flow
MICROTASKS: [Link] AND PROMISES
Microtasks execute between event loop phases, providing a way to schedule work with higher priority than regular callbacks.
Two microtask queues exist:
1. [Link] queue - Highest priority, processed first
2. Promise microtask queue - Processes after nextTick
Warning: Recursive [Link]() calls can starve the event loop, preventing I/O callbacks from executing.
© SKILLING | REFCARD | APRIL 2026 5
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
Best practices:
Use setImmediate() for deferred execution when possible
Reserve [Link]() for cases requiring immediate async execution
Promises automatically use the microtask queue via .then()
JAVASCRIPT Microtask Queue Behavior
// Demonstrating microtask priority
setImmediate(() => [Link]('1. setImmediate'));
setTimeout(() => [Link]('2. setTimeout'), 0);
[Link]()
.then(() => {
[Link]('3. Promise 1');
return [Link]();
})
.then(() => [Link]('4. Promise 2'));
[Link](() => {
[Link]('5. nextTick 1');
[Link](() => [Link]('6. nextTick 2'));
});
[Link]('7. Synchronous');
// Output:
// 7. Synchronous
// 5. nextTick 1
// 6. nextTick 2
// 3. Promise 1
// 4. Promise 2
// 2. setTimeout
// 1. setImmediate
AS Y N C H R O N O U S PAT T E R N S I N N O D E . J S
[Link] provides multiple patterns for handling asynchronous operations. Understanding when to use each pattern is crucial for writing maintainable code.
This section covers the evolution from callbacks to Promises to async/await, along with practical patterns for common scenarios.
Evolution of Async Patterns in [Link]
© SKILLING | REFCARD | APRIL 2026 6
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
Comparing Async Patterns
PATTERN ERROR HANDLING READABILITY BEST USE CASE
Callbacks Error-first parameter Poor for complex flows Simple single async operations, legacy APIs
Promises .catch() chains Good, chainable Sequential async operations, parallel with [Link]
async/await try/catch blocks Excellent, synchronous-looking Complex async logic, conditionals, loops
JAVASCRIPT The Same Operation in Three Patterns
const fs = require('fs');
const { promisify } = require('util');
const fsPromises = require('fs').promises;
// Pattern 1: Callbacks (traditional)
[Link]('[Link]', 'utf8', (err, data) => {
if (err) {
[Link]('Callback error:', [Link]);
return;
}
[Link]('Callback result:', [Link](data));
});
// Pattern 2: Promises (using promisify or [Link])
[Link]('[Link]', 'utf8')
.then(data => [Link]('Promise result:', [Link](data)))
.catch(err => [Link]('Promise error:', [Link]));
// Pattern 3: async/await (modern approach)
async function readConfig() {
try {
const data = await [Link]('[Link]', 'utf8');
[Link]('Async/await result:', [Link](data));
} catch (err) {
[Link]('Async error:', [Link]);
}
}
readConfig();
CALLBACKS AND ERROR-FIRST CONVENTION
The error-first callback pattern is [Link]'s original async convention. The callback function receives an error object as its first parameter, followed by result data.
Convention rules:
First parameter is always the error (or null if success)
Always check for errors before processing results
Never throw inside callbacks—pass errors to the callback instead
Common pitfalls:
Callback hell - Deeply nested callbacks become unreadable
Forgetting to return after error handling
Calling callback multiple times accidentally
JAVASCRIPT Proper Callback Error Handling
const fs = require('fs');
function processFile(filename, callback) {
[Link](filename, 'utf8', (err, data) => {
if (err) {
// Always return after calling callback with error
return callback(err, null);
}
try {
const parsed = [Link](data);
callback(null, parsed);
} catch (parseError) {
// Pass parsing errors to callback, don't throw
callback(parseError, null);
}
© SKILLING | REFCARD | APRIL 2026 7
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
});
}
// Usage
processFile('[Link]', (err, result) => {
if (err) {
[Link]('Error:', [Link]);
return;
}
[Link]('Success:', result);
});
PROMISES AND PROMISE COMBINATORS
Promises represent the eventual completion or failure of an async operation. They provide chainable .then() and .catch() methods for handling results and
errors.
Promise states:
Pending - Initial state, operation in progress
Fulfilled - Operation completed successfully
Rejected - Operation failed with an error
Promise combinators for parallel operations:
[Link]([...]) - Resolves when ALL succeed, rejects on ANY failure
[Link]([...]) - Waits for all, returns status of each
[Link]([...]) - Resolves/rejects with first settled promise
[Link]([...]) - Resolves with first success, rejects if ALL fail
JAVASCRIPT Promise Combinators in Action
const fetchUser = (id) =>
new Promise((resolve) =>
setTimeout(() => resolve({ id, name: `User${id}` }), 100 * id)
);
const fetchWithError = (id) =>
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Failed ${id}`)), 50)
);
// [Link] - All must succeed
[Link]([fetchUser(1), fetchUser(2), fetchUser(3)])
.then(users => [Link]('All users:', users))
.catch(err => [Link]('One failed:', err));
// [Link] - Get all results regardless of success/failure
[Link]([fetchUser(1), fetchWithError(2), fetchUser(3)])
.then(results => {
[Link]((result, i) => {
if ([Link] === 'fulfilled') {
[Link](`Success ${i}:`, [Link]);
} else {
[Link](`Failed ${i}:`, [Link]);
}
});
});
// [Link] - First to settle wins
[Link]([fetchUser(3), fetchUser(1)])
.then(first => [Link]('First result:', first));
ASYNC/AWAIT BEST PRACTICES
async/await provides synchronous-looking syntax for asynchronous code. An async function always returns a Promise, and await pauses execution until the
Promise settles.
Best practices:
Always wrap in try/catch for error handling
Avoid sequential awaits when operations are independent
Use [Link] for parallel independent operations
© SKILLING | REFCARD | APRIL 2026 8
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
Don't use await inside forEach - Use for...of or [Link] with map
Common mistakes:
Forgetting that async functions return Promises
Sequential awaits causing unnecessary delays
Unhandled Promise rejections from missing try/catch
JAVASCRIPT Parallel vs Sequential async/await
// Simulated async operations
const fetchData = (name, ms) =>
new Promise(resolve => setTimeout(() => resolve(`${name} data`), ms));
// BAD: Sequential awaits (takes 600ms)
async function sequentialFetch() {
const start = [Link]();
const a = await fetchData('A', 200);
const b = await fetchData('B', 200);
const c = await fetchData('C', 200);
[Link](`Sequential: ${[Link]() - start}ms`, [a, b, c]);
}
// GOOD: Parallel execution (takes 200ms)
async function parallelFetch() {
const start = [Link]();
const [a, b, c] = await [Link]([
fetchData('A', 200),
fetchData('B', 200),
fetchData('C', 200)
]);
[Link](`Parallel: ${[Link]() - start}ms`, [a, b, c]);
}
// Correct async iteration
async function processItems(items) {
// Use for...of for sequential processing
for (const item of items) {
await processItem(item);
}
// Or [Link] for parallel processing
await [Link]([Link](item => processItem(item)));
}
ERROR HANDLING STRATEGIES
Proper error handling in async code prevents crashes and improves debugging. [Link] provides multiple mechanisms for catching and handling errors.
Error handling layers:
1. try/catch - Local error handling in async functions
2. Promise .catch() - Chain-level error handling
3. Event listeners - For streams and EventEmitters
4. Global handlers - Last resort catch-all
Always set up global handlers:
[Link]('unhandledRejection') - Unhandled Promise rejections
[Link]('uncaughtException') - Uncaught synchronous errors
Note: Global handlers should log and exit gracefully, not attempt recovery.
JAVASCRIPT Comprehensive Error Handling Setup
// Global unhandled rejection handler
[Link]('unhandledRejection', (reason, promise) => {
[Link]('Unhandled Rejection at:', promise);
[Link]('Reason:', reason);
// In production, log to monitoring service and exit
[Link](1);
});
// Global uncaught exception handler
[Link]('uncaughtException', (error) => {
© SKILLING | REFCARD | APRIL 2026 9
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
[Link]('Uncaught Exception:', error);
// Cleanup and exit - don't try to continue
[Link](1);
});
// Wrapper function for async route handlers
const asyncHandler = (fn) => (req, res, next) => {
[Link](fn(req, res, next)).catch(next);
};
// Custom error class for operational errors
class AppError extends Error {
constructor(message, statusCode) {
super(message);
[Link] = statusCode;
[Link] = true;
[Link](this, [Link]);
}
}
E X P R E S S . J S F U N DA M E N TA L S A N D A P P L I CAT I O N S T R U C T U R E
[Link] is the most popular [Link] web framework, providing a minimal and flexible foundation for building web applications and APIs. It simplifies routing,
middleware management, and HTTP handling.
This section covers Express application setup, project structure best practices, and core configuration options.
[Link] Request-Response Cycle
JAVASCRIPT Basic Express Application Setup
const express = require('express');
const app = express();
// Built-in middleware for parsing
[Link]([Link]()); // Parse JSON bodies
[Link]([Link]({ extended: true })); // Parse URL-encoded bodies
[Link]([Link]('public')); // Serve static files
// Basic route
[Link]('/', (req, res) => {
[Link]({ message: 'Welcome to the API', version: '1.0.0' });
});
// Route with parameters
[Link]('/users/:id', (req, res) => {
const userId = [Link];
[Link]({ userId, name: `User ${userId}` });
});
// Error handling middleware (must be last)
© SKILLING | REFCARD | APRIL 2026 10
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
[Link]((err, req, res, next) => {
[Link]([Link]);
[Link](500).json({ error: 'Something went wrong!' });
});
// Start server
const PORT = [Link] || 3000;
[Link](PORT, () => {
[Link](`Server running on [Link]
});
INSTALLING AND CONFIGURING EXPRESS
Setting up an Express project requires [Link] and npm. Follow these steps for a proper project initialization:
1. Create project directory and initialize:
```bash
mkdir my-api && cd my-api
npm init -y
`
2. Install Express and common dependencies:
```bash
npm install express dotenv cors helmet
npm install -D nodemon
`
Essential packages:
express - Web framework
dotenv - Environment variable management
cors - Cross-Origin Resource Sharing
helmet - Security headers
nodemon - Auto-restart during development
JSON [Link] Scripts Configuration
{
"name": "my-api",
"version": "1.0.0",
"main": "src/[Link]",
"scripts": {
"start": "node src/[Link]",
"dev": "nodemon src/[Link]",
"test": "jest",
"lint": "eslint src/"
},
"dependencies": {
"express": "^4.18.2",
"dotenv": "^16.3.1",
"cors": "^2.8.5",
"helmet": "^7.1.0"
},
"devDependencies": {
"nodemon": "^3.0.2",
"jest": "^29.7.0"
}
}
PROJECT STRUCTURE BEST PRACTICES
A well-organized project structure improves maintainability and scalability. Follow the separation of concerns principle.
Recommended structure:
`
project/
├── src/
│ ├── [Link] # App entry point
© SKILLING | REFCARD | APRIL 2026 11
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
│ ├── [Link] # Express app setup
│ ├── config/ # Configuration files
│ ├── routes/ # Route definitions
│ ├── controllers/ # Request handlers
│ ├── services/ # Business logic
│ ├── models/ # Data models
│ ├── middleware/ # Custom middleware
│ └── utils/ # Helper functions
├── tests/ # Test files
├── .env # Environment variables
└── [Link]
Key principle: Keep [Link] clean—delegate routes and logic to separate modules.
Express Application Architecture Layers
THE APP AND REQUEST/RESPONSE OBJECTS
Express provides three core objects you'll use constantly:
app - The Express application:
[Link]() - Mount middleware
[Link]/post/put/delete() - Define routes
[Link]() - Configure app settings
[Link]() - Start the server
req (Request) - Incoming request data:
[Link] - URL route parameters
[Link] - Query string parameters
[Link] - Request body (requires parsing middleware)
[Link] - HTTP headers
res (Response) - Outgoing response methods:
[Link]() - Send JSON response
[Link]() - Set HTTP status code
[Link]() - Send various response types
[Link]() - Redirect to another URL
JAVASCRIPT Working with Request and Response Objects
© SKILLING | REFCARD | APRIL 2026 12
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
[Link]('/products', (req, res) => {
// Query parameters: /products?category=electronics&limit=10
const { category, limit = 20, page = 1 } = [Link];
// Request headers
const userAgent = [Link]('User-Agent');
const authToken = [Link]('Authorization');
[Link](`Request from: ${[Link]}`);
// Send response with status and headers
res
.status(200)
.set('X-Custom-Header', 'my-value')
.json({
category,
limit: parseInt(limit),
page: parseInt(page),
products: []
});
});
[Link]('/products', (req, res) => {
// Request body (requires [Link]() middleware)
const { name, price, description } = [Link];
if (!name || !price) {
return [Link](400).json({ error: 'Name and price required' });
}
// Create product and respond with 201 Created
const newProduct = { id: [Link](), name, price, description };
[Link](201).json(newProduct);
});
ENVIRONMENT CONFIGURATION
Environment variables separate configuration from code, enabling different settings for development, testing, and production.
Using dotenv package:
1. Create .env file (never commit to git!):
`
PORT=3000
NODE_ENV=development
DB_HOST=localhost
DB_PORT=5432
API_KEY=your-secret-key
`
2. Load at app startup:
```javascript
require('dotenv').config();
`
3. Access via [Link].VARIABLE_NAME
Best practices:
Create .[Link] with placeholder values for documentation
Add .env to .gitignore
Validate required variables at startup
Use different .env files per environment
JAVASCRIPT Environment Configuration Module
// src/config/[Link]
require('dotenv').config();
© SKILLING | REFCARD | APRIL 2026 13
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
const requiredEnvVars = ['NODE_ENV', 'PORT', 'DATABASE_URL'];
// Validate required environment variables
for (const envVar of requiredEnvVars) {
if (![Link][envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`);
}
}
[Link] = {
nodeEnv: [Link].NODE_ENV || 'development',
port: parseInt([Link], 10) || 3000,
db: {
url: [Link].DATABASE_URL,
pool: {
min: parseInt([Link].DB_POOL_MIN, 10) || 2,
max: parseInt([Link].DB_POOL_MAX, 10) || 10
}
},
jwt: {
secret: [Link].JWT_SECRET,
expiresIn: [Link].JWT_EXPIRES_IN || '1d'
},
isDevelopment: [Link].NODE_ENV === 'development',
isProduction: [Link].NODE_ENV === 'production'
};
[Link] ROUTING IN DEPTH
Routing refers to how an application responds to client requests at specific endpoints. Express provides a powerful routing system that supports parameters, query
strings, and modular router organization.
Mastering routing patterns is essential for building clean, maintainable APIs.
Express Router Modular Architecture
HTTP Methods and RESTful Conventions
HTTP METHOD CRUD OPERATION EXAMPLE ROUTE DESCRIPTION
GET Read GET /users Retrieve all resources
GET Read GET /users/:id Retrieve single resource
POST Create POST /users Create new resource
PUT Update PUT /users/:id Full resource update
PATCH Update PATCH /users/:id Partial resource update
DELETE Delete DELETE /users/:id Remove resource
© SKILLING | REFCARD | APRIL 2026 14
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
JAVASCRIPT Complete Modular Router Implementation
// src/routes/[Link]
const express = require('express');
const router = [Link]();
const usersController = require('../controllers/usersController');
const { authenticate, authorize } = require('../middleware/auth');
const { validateUser } = require('../middleware/validation');
// GET /api/users - List all users
[Link]('/', authenticate, [Link]);
// GET /api/users/:id - Get user by ID
[Link]('/:id', authenticate, [Link]);
// POST /api/users - Create new user
[Link]('/', validateUser, [Link]);
// PUT /api/users/:id - Update user
[Link]('/:id', authenticate, authorize('admin'), validateUser, [Link]);
// DELETE /api/users/:id - Delete user
[Link]('/:id', authenticate, authorize('admin'), [Link]);
[Link] = router;
// src/[Link]
const express = require('express');
const usersRouter = require('./routes/users');
const productsRouter = require('./routes/products');
const app = express();
[Link]([Link]());
[Link]('/api/users', usersRouter);
[Link]('/api/products', productsRouter);
[Link] = app;
ROUTE PARAMETERS AND PATTERNS
Express supports dynamic route segments using colon-prefixed parameters. These parameters are captured in [Link] .
Parameter types:
Required: /users/:id - Must be present
Optional: /users/:id? - May be omitted
Multiple: /users/:userId/posts/:postId - Nested resources
Regex constrained: /users/:id(\\d+) - Only match digits
Common patterns:
`
/api/v1/resources → Collection
/api/v1/resources/:id → Single resource
/api/v1/resources/:id/sub → Nested collection
`
Tip: Validate parameters early using middleware to prevent invalid data from reaching controllers.
JAVASCRIPT Route Parameter Patterns and Validation
// Basic parameter
[Link]('/users/:id', (req, res) => {
const { id } = [Link]; // String: "123"
[Link]({ userId: id });
});
// Multiple parameters
[Link]('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = [Link];
[Link]({ userId, postId });
© SKILLING | REFCARD | APRIL 2026 15
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
});
// Optional parameter
[Link]('/archive/:year/:month?', (req, res) => {
const { year, month = 'all' } = [Link];
[Link]({ year, month });
});
// Parameter middleware - runs for any route with :id
[Link]('id', (req, res, next, id) => {
// Validate ID format
if (!/^[0-9a-fA-F]{24}$/.test(id)) {
return [Link](400).json({ error: 'Invalid ID format' });
}
// Attach to request for later use
[Link] = id;
next();
});
QUERY STRINGS AND REQUEST BODY
Beyond route parameters, Express handles data from query strings and request bodies.
Query strings ( [Link] ):
Appended to URL: /search?q=node&limit=10
Always strings—parse numbers manually
Good for filtering, pagination, sorting
Request body ( [Link] ):
Requires parsing middleware ( [Link]() )
Used for POST/PUT/PATCH data
Supports JSON, URL-encoded, multipart
Best practices:
Validate and sanitize all input
Use default values for optional parameters
Return 400 for invalid input
Document expected parameters in API docs
JAVASCRIPT Query String Handling with Pagination
// GET /api/products?category=electronics&minPrice=100&maxPrice=500&sort=price&order=asc&page=2&limit=20
[Link]('/api/products', (req, res) => {
// Extract and parse query parameters with defaults
const {
category,
minPrice = 0,
maxPrice = Infinity,
sort = 'createdAt',
order = 'desc',
page = 1,
limit = 10
} = [Link];
// Parse numeric values
const filters = {
category,
minPrice: parseFloat(minPrice),
maxPrice: parseFloat(maxPrice)
};
const pagination = {
page: [Link](1, parseInt(page)),
limit: [Link](100, [Link](1, parseInt(limit))), // Cap at 100
sort,
order: order === 'asc' ? 1 : -1
};
// Calculate skip for pagination
const skip = ([Link] - 1) * [Link];
© SKILLING | REFCARD | APRIL 2026 16
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
[Link]({
filters,
pagination: { ...pagination, skip },
data: []
});
});
ROUTER CHAINING AND METHOD HANDLERS
Express Router allows chaining multiple handlers and grouping routes by resource. The [Link]() method enables chaining HTTP methods for the same path.
Route chaining benefits:
Reduces repetition of route paths
Groups related methods visually
Makes route definitions more readable
Handler chaining ( next() ):
Multiple handlers for single route
Each calls next() to pass control
Useful for validation → authentication → controller flow
Example:
```javascript
[Link]('/:id')
.get(getOne)
.put(updateOne)
.delete(deleteOne);
`
JAVASCRIPT Route Chaining and Multiple Handlers
const router = [Link]();
// Method chaining on same path
[Link]('/')
.get((req, res) => {
[Link]({ action: 'List all items' });
})
.post((req, res) => {
[Link](201).json({ action: 'Create item', data: [Link] });
});
[Link]('/:id')
.get((req, res) => {
[Link]({ action: 'Get item', id: [Link] });
})
.put((req, res) => {
[Link]({ action: 'Update item', id: [Link] });
})
.delete((req, res) => {
[Link](204).send();
});
// Multiple handlers - validation then controller
const validateId = (req, res, next) => {
if (!/^\d+$/.test([Link])) {
return [Link](400).json({ error: 'ID must be numeric' });
}
next();
};
const checkExists = async (req, res, next) => {
const item = await findById([Link]);
if (!item) {
return [Link](404).json({ error: 'Not found' });
}
[Link] = item; // Attach for next handler
next();
© SKILLING | REFCARD | APRIL 2026 17
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
};
[Link]('/:id', validateId, checkExists, (req, res) => {
[Link]([Link]);
});
E X P R E S S . J S M I D D L E WA R E D E E P D I V E
Middleware functions are the backbone of Express applications. They have access to the request and response objects and can modify them, end the request-
response cycle, or call the next middleware.
Understanding middleware is crucial for authentication, logging, error handling, and request processing.
Middleware Execution Pipeline
Common Middleware Categories and Examples
CATEGORY PURPOSE POPULAR PACKAGES CUSTOM EXAMPLE
Body Parsing Parse request bodies [Link](), [Link]() Custom XML parser
Authentication Verify user identity passport, express-jwt JWT validation middleware
Authorization Check permissions casl, accesscontrol Role-based access control
Logging Request/response logging morgan, winston Custom audit logger
Security Protect against attacks helmet, cors, csurf Rate limiter
Validation Validate input data express-validator, joi Schema validation
Error Handling Catch and format errors express-async-errors Global error handler
JAVASCRIPT Complete Middleware Setup Example
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const app = express();
// Security middleware
[Link](helmet()); // Sets security headers
// CORS configuration
[Link](cors({
origin: [Link].ALLOWED_ORIGINS?.split(',') || '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
© SKILLING | REFCARD | APRIL 2026 18
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
// Logging middleware
[Link](morgan('combined')); // Apache combined log format
// Body parsing middleware
[Link]([Link]({ limit: '10mb' }));
[Link]([Link]({ extended: true, limit: '10mb' }));
// Custom request timing middleware
[Link]((req, res, next) => {
[Link] = [Link]();
[Link]('finish', () => {
const duration = [Link]() - [Link];
[Link](`${[Link]} ${[Link]} - ${[Link]} [${duration}ms]`);
});
next();
});
// Routes
[Link]('/api', apiRoutes);
// 404 handler
[Link]((req, res) => {
[Link](404).json({ error: 'Route not found' });
});
// Global error handler (must be last)
[Link]((err, req, res, next) => {
[Link]([Link]);
[Link]([Link] || 500).json({
error: [Link].NODE_ENV === 'production'
? 'Internal server error'
: [Link]
});
});
MIDDLEWARE TYPES AND EXECUTION ORDER
Express middleware falls into five categories:
1. Application-level - Bound to [Link]() or [Link]()
2. Router-level - Bound to [Link]()
3. Error-handling - Four parameters: (err, req, res, next)
4. Built-in - [Link]() , [Link]() , etc.
5. Third-party - External packages like helmet , cors
Execution order matters! Middleware runs in the order defined:
Place security middleware (helmet, cors) first
Body parsers before routes that need [Link]
Authentication before protected routes
Error handlers last
Critical: Always call next() or send a response, otherwise requests hang.
JAVASCRIPT Middleware Execution Order Demonstration
const express = require('express');
const app = express();
// 1. Runs for ALL requests
[Link]((req, res, next) => {
[Link]('1. Application middleware - all routes');
next();
});
// 2. Runs only for /api/* paths
[Link]('/api', (req, res, next) => {
[Link]('2. Path-specific middleware - /api/*');
next();
});
// 3. Runs only for GET /api/users
[Link]('/api/users',
© SKILLING | REFCARD | APRIL 2026 19
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
(req, res, next) => {
[Link]('3. Route-specific middleware');
next();
},
(req, res) => {
[Link]('4. Route handler');
[Link]({ users: [] });
}
);
// Request to GET /api/users outputs:
// 1. Application middleware - all routes
// 2. Path-specific middleware - /api/*
// 3. Route-specific middleware
// 4. Route handler
CUSTOM AUTHENTICATION MIDDLEWARE
Authentication middleware verifies user identity before allowing access to protected routes. Common approaches:
JWT (JSON Web Tokens) - Stateless, scalable
Session-based - Server stores session data
API Keys - Simple service-to-service auth
OAuth - Third-party authentication
JWT authentication flow:
1. Client sends token in Authorization: Bearer <token> header
2. Middleware extracts and verifies token
3. Decoded user data attached to [Link]
4. Protected routes access [Link]
Best practice: Create reusable auth middleware factory functions for different permission levels.
JWT Authentication Flow
JAVASCRIPT JWT Authentication Middleware Implementation
const jwt = require('jsonwebtoken');
// Authentication middleware
const authenticate = (req, res, next) => {
// Get token from header
const authHeader = [Link];
if (!authHeader || ) {
return [Link](401).json({ error: 'No token provided' });
}
const token = [Link](' ')[1];
© SKILLING | REFCARD | APRIL 2026 20
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
try {
// Verify token
const decoded = [Link](token, [Link].JWT_SECRET);
[Link] = decoded; // Attach user to request
next();
} catch (err) {
if ([Link] === 'TokenExpiredError') {
return [Link](401).json({ error: 'Token expired' });
}
return [Link](401).json({ error: 'Invalid token' });
}
};
// Authorization middleware factory
const authorize = (...roles) => {
return (req, res, next) => {
if (![Link]) {
return [Link](401).json({ error: 'Not authenticated' });
}
if () {
return [Link](403).json({ error: 'Insufficient permissions' });
}
next();
};
};
// Usage
[Link]('/admin/dashboard', authenticate, authorize('admin'), [Link]);
[Link]('/profile', authenticate, [Link]);
INPUT VALIDATION MIDDLEWARE
Input validation prevents malformed or malicious data from reaching your application logic. Always validate on the server—client-side validation can be bypassed.
Validation strategies:
express-validator - Chain-based validation
Joi - Schema-based validation
Zod - TypeScript-first validation
What to validate:
Type - Is it a string, number, array?
Format - Email, UUID, date format?
Range - Min/max length, numeric bounds?
Required - Is the field mandatory?
Sanitization - Trim, escape, normalize
Pattern: Validate in middleware, handle errors consistently.
JAVASCRIPT Input Validation with express-validator
const { body, param, query, validationResult } = require('express-validator');
// Validation error handler middleware
const validate = (req, res, next) => {
const errors = validationResult(req);
if (![Link]()) {
return [Link](400).json({
error: 'Validation failed',
details: [Link]().map(err => ({
field: [Link],
message: [Link]
}))
});
}
next();
};
// User creation validation rules
const createUserValidation = [
body('email')
© SKILLING | REFCARD | APRIL 2026 21
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
.isEmail().withMessage('Invalid email format')
.normalizeEmail()
.custom(async (email) => {
const exists = await [Link]({ email });
if (exists) throw new Error('Email already registered');
}),
body('password')
.isLength({ min: 8 }).withMessage('Password must be at least 8 characters')
.matches(/\d/).withMessage('Password must contain a number')
.matches(/[A-Z]/).withMessage('Password must contain uppercase letter'),
body('name')
.trim()
.notEmpty().withMessage('Name is required')
.isLength({ max: 100 }).withMessage('Name too long'),
body('age')
.optional()
.isInt({ min: 0, max: 150 }).withMessage('Invalid age'),
validate // Error handler middleware at the end
];
// Apply validation
[Link]('/users', createUserValidation, [Link]);
ERROR HANDLING MIDDLEWARE
Error handling middleware catches errors from route handlers and other middleware. It must have four parameters: (err, req, res, next) .
Error handling best practices:
1. Define custom error classes for operational errors
2. Distinguish operational vs programming errors
3. Log errors appropriately (detailed in dev, minimal in prod)
4. Send consistent error responses
5. Handle async errors with wrapper or express-async-errors
Error response structure:
```json
{
"error": "Human-readable message",
"code": "ERROR_CODE",
"statusCode": 400,
"details": []
}
`
Important: Error middleware must be registered AFTER all routes.
JAVASCRIPT Comprehensive Error Handling Setup
// Custom error classes
class AppError extends Error {
constructor(message, statusCode, code = 'APP_ERROR') {
super(message);
[Link] = statusCode;
[Link] = code;
[Link] = true;
[Link](this, [Link]);
}
}
class NotFoundError extends AppError {
constructor(resource = 'Resource') {
super(`${resource} not found`, 404, 'NOT_FOUND');
}
}
class ValidationError extends AppError {
constructor(details) {
super('Validation failed', 400, 'VALIDATION_ERROR');
[Link] = details;
© SKILLING | REFCARD | APRIL 2026 22
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
}
}
// Async handler wrapper
const asyncHandler = (fn) => (req, res, next) => {
[Link](fn(req, res, next)).catch(next);
};
// Global error handler
const errorHandler = (err, req, res, next) => {
// Log error
[Link](`[${new Date().toISOString()}] ${[Link]}`);
// Default values
let statusCode = [Link] || 500;
let message = [Link] || 'Internal server error';
let code = [Link] || 'INTERNAL_ERROR';
// Hide details in production for non-operational errors
if ([Link].NODE_ENV === 'production' && ![Link]) {
message = 'Something went wrong';
code = 'INTERNAL_ERROR';
}
[Link](statusCode).json({
error: message,
code,
...([Link] && { details: [Link] }),
...([Link].NODE_ENV === 'development' && { stack: [Link] })
});
};
// Usage
[Link]('/api', apiRoutes);
[Link](errorHandler); // Must be last
© SKILLING | REFCARD | APRIL 2026 23
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
© SKILLING | REFCARD | APRIL 2026 24
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
© SKILLING | REFCARD | APRIL 2026 25
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
© SKILLING | REFCARD | APRIL 2026 26
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
© SKILLING | REFCARD | APRIL 2026 27
Skilling. REFCARD | GETTING STARTED WITH FULL STACK: [Link] RUNTIME & … RC-C4-FSD-2026
CONCLUSION
Key Takeaways
This refcard covered the essential concepts of [Link] runtime architecture and [Link] web development. Understanding the event loop and its phases is
fundamental to writing efficient, non-blocking applications. The V8 engine and libuv work together to provide [Link] with its speed and cross-platform async I/O
capabilities.
[Link] provides a minimal but powerful framework for building web applications. Key concepts include:
Modular routing with [Link]() RESTful API design patterns Middleware for cross-cutting concerns (authentication, validation, logging) Proper error handling
with custom error classes Common Beginner Mistakes to Avoid
Blocking the event loop with synchronous operations or CPU-intensive tasks Forgetting to call next() in middleware, causing requests to hang Not handling async
errors properly, leading to unhandled rejections Sequential awaits when operations could run in parallel with [Link]() Skipping input validation, trusting client-
side data Placing error middleware before routes (it won't catch errors) Storing secrets in code instead of environment variables Not setting proper security headers
(use helmet!) Next Steps for Further Learning
Database Integration: Learn MongoDB with Mongoose or PostgreSQL with Sequelize/Prisma Authentication: Implement JWT, OAuth 2.0, and session-based auth
with [Link] Testing: Write unit and integration tests with Jest and Supertest TypeScript: Add type safety to your [Link] and Express applications Performance:
Explore clustering, caching with Redis, and load balancing WebSockets: Real-time communication with [Link] Containerization: Deploy with Docker and
orchestrate with Kubernetes API Documentation: Generate docs with Swagger/OpenAPI Continue building projects and exploring the vast [Link] ecosystem to
solidify your full-stack development skills.
© SKILLING | REFCARD | APRIL 2026 28