1. Introduction to Node.js
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It allows you to run JavaScript on the server side, enabling full-stack JavaScript development.
What is Node.js?
Runtime Environment: Execute JavaScript outside the browser
Event-Driven: Non-blocking, asynchronous I/O operations
Single-Threaded: Uses an event loop for concurrency
Cross-Platform: Runs on Windows, macOS, and Linux
NPM Ecosystem: Largest package repository in the world
Why Node.js?
Fast: Built on Google's V8 engine
Scalable: Handle thousands of concurrent connections
JavaScript Everywhere: Same language for frontend and backend
Large Community: Extensive libraries and frameworks
Real-time Applications: Perfect for chat apps, gaming, collaboration tools
Node.js Use Cases
Perfect for:
Web APIs: RESTful services and GraphQL
Real-time Apps: Chat applications, live updates
Microservices: Lightweight, scalable services
Command Line Tools: Build automation, utilities
IoT Applications: Handle sensor data and device communication
💡 Tip: Node.js is not suitable for CPU-intensive tasks due to its single-threaded nature. It excels at I/O-intensive applications.
2. Setting Up Node.js
Installation
# Download from nodejs.org or use package managers
# macOS (using Homebrew)
brew install node
# Ubuntu/Debian
sudo apt update
sudo apt install nodejs npm
# Windows (using Chocolatey)
choco install nodejs
# Verify installation
node --version
npm --version
Node Version Manager (NVM)
# Install NVM (Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Install and use specific Node version
nvm install 18.17.0
nvm use 18.17.0
nvm alias default 18.17.0
# List installed versions
nvm list
Your First Node.js Program
// hello.js
console.log("Hello, Node.js!");
console.log("Current directory:", __dirname);
console.log("Current file:", __filename);
console.log("Node version:", process.version);
console.log("Platform:", process.platform);
# Run the program
node hello.js
Try Node.js:
Run Node.js Example
Click to see Node.js in action!
3. Node.js Basics
Global Objects
// Global objects available in Node.js
console.log("Global object:", global);
console.log("Process object:", process.pid);
console.log("Current working directory:", process.cwd());
console.log("Environment variables:", process.env.NODE_ENV);
// Timers
setTimeout(() => {
console.log("This runs after 2 seconds");
}, 2000);
setInterval(() => {
console.log("This runs every 3 seconds");
}, 3000);
// Buffer for binary data
const buffer = Buffer.from("Hello World", "utf8");
console.log("Buffer:", buffer);
console.log("Buffer to string:", buffer.toString());
Process Object
// Command line arguments
console.log("Arguments:", process.argv);
// Environment variables
console.log("NODE_ENV:", process.env.NODE_ENV || "development");
console.log("PORT:", process.env.PORT || 3000);
// Process events
process.on("exit", (code) => {
console.log(`Process exiting with code: ${code}`);
});
process.on("uncaughtException", (error) => {
console.error("Uncaught Exception:", error);
process.exit(1);
});
// Exit the process
// process.exit(0);
Event Loop and Asynchronous Programming
// Synchronous vs Asynchronous
console.log("Start");
// Asynchronous - goes to callback queue
setTimeout(() => {
console.log("Timeout callback");
}, 0);
// Asynchronous - goes to microtask queue (higher priority)
Promise.resolve().then(() => {
console.log("Promise resolved");
});
// Synchronous
console.log("End");
// Output order: Start, End, Promise resolved, Timeout callback
⚠️ Important: Understanding the event loop is crucial for Node.js development. Microtasks (Promises) have higher priority than macrotasks (setTimeout, setInterval).
4. Modules and Require
CommonJS Modules
// math.js - Creating a module
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
// Export functions
module.exports = {
add,
subtract,
multiply
};
// Alternative export syntax
// exports.add = add;
// exports.subtract = subtract;
// app.js - Using the module
const math = require('./math');
// or destructuring
const { add, subtract } = require('./math');
console.log("5 + 3 =", math.add(5, 3));
console.log("10 - 4 =", subtract(10, 4));
// Built-in modules
const path = require('path');
const os = require('os');
console.log("File extension:", path.extname('file.txt'));
console.log("Operating System:", os.platform());
console.log("Free memory:", os.freemem());
ES6 Modules (ESM)
// package.json - Enable ES modules
{
"type": "module"
}
// math.mjs - ES6 module
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export default function multiply(a, b) {
return a * b;
}
// app.mjs - Using ES6 modules
import multiply, { add, subtract } from './math.mjs';
import path from 'path';
console.log("5 + 3 =", add(5, 3));
console.log("5 * 3 =", multiply(5, 3));
Core Modules
// Path module
const path = require('path');
console.log("Join paths:", path.join('/users', 'john', 'documents'));
console.log("Resolve path:", path.resolve('file.txt'));
console.log("Parse path:", path.parse('/users/john/file.txt'));
// OS module
const os = require('os');
console.log("Platform:", os.platform());
console.log("Architecture:", os.arch());
console.log("CPU count:", os.cpus().length);
console.log("Total memory:", os.totalmem());
console.log("Home directory:", os.homedir());
// URL module
const url = require('url');
const myUrl = new URL('https://example.com:8080/path?name=john&age=30');
console.log("Protocol:", myUrl.protocol);
console.log("Host:", myUrl.host);
console.log("Pathname:", myUrl.pathname);
console.log("Search params:", myUrl.searchParams.get('name'));
🏋️ Exercise 1:
Create a module that exports functions to calculate the area and perimeter of different shapes (circle, rectangle, triangle).
5. NPM (Node Package Manager)
Package.json
// Initialize a new project
npm init
npm init -y // Skip questions
// package.json structure
{
"name": "my-node-app",
"version": "1.0.0",
"description": "My awesome Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"keywords": ["node", "javascript"],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.5.0"
}
}
Installing Packages
# Install packages
npm install express # Production dependency
npm install -D nodemon # Development dependency
npm install -g nodemon # Global installation
# Install specific version
npm install express@4.18.2
# Install from package.json
npm install
# Update packages
npm update
npm outdated
# Remove packages
npm uninstall express
npm uninstall -D nodemon
Popular NPM Packages
Essential Packages:
express: Web framework
lodash: Utility library
axios: HTTP client
moment: Date manipulation
mongoose: MongoDB ODM
bcrypt: Password hashing
jsonwebtoken: JWT tokens
dotenv: Environment variables
cors: Cross-origin resource sharing
helmet: Security middleware
Using NPM Packages
// Install: npm install lodash axios
const _ = require('lodash');
const axios = require('axios');
// Using lodash
const numbers = [1, 2, 3, 4, 5];
const doubled = _.map(numbers, n => n * 2);
console.log("Doubled:", doubled);
const users = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
{ name: 'Bob', age: 35 }
];
const sortedUsers = _.sortBy(users, 'age');
console.log("Sorted by age:", sortedUsers);
// Using axios for HTTP requests
async function fetchData() {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
console.log("Post title:", response.data.title);
} catch (error) {
console.error("Error fetching data:", error.message);
}
}
fetchData();
NPM Scripts
// package.json scripts
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest",
"build": "webpack --mode production",
"lint": "eslint .",
"format": "prettier --write ."
}
}
# Run scripts
npm start
npm run dev
npm test
npm run build
6. File System Operations
Reading and Writing Files
const fs = require('fs');
const path = require('path');
// Synchronous file operations
try {
// Write file
fs.writeFileSync('example.txt', 'Hello, Node.js!');
console.log('File written successfully');
// Read file
const data = fs.readFileSync('example.txt', 'utf8');
console.log('File content:', data);
// Check if file exists
if (fs.existsSync('example.txt')) {
console.log('File exists');
}
} catch (error) {
console.error('Error:', error.message);
}
// Asynchronous file operations (recommended)
fs.writeFile('async-example.txt', 'Hello, Async!', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('Async file written');
fs.readFile('async-example.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('Async file content:', data);
});
});
Promises and Async/Await with Files
const fs = require('fs').promises;
async function fileOperations() {
try {
// Write file
await fs.writeFile('promise-example.txt', 'Hello, Promises!');
console.log('Promise file written');
// Read file
const data = await fs.readFile('promise-example.txt', 'utf8');
console.log('Promise file content:', data);
// Get file stats
const stats = await fs.stat('promise-example.txt');
console.log('File size:', stats.size, 'bytes');
console.log('Created:', stats.birthtime);
console.log('Modified:', stats.mtime);
// Append to file
await fs.appendFile('promise-example.txt', '\nAppended text');
// Read updated content
const updatedData = await fs.readFile('promise-example.txt', 'utf8');
console.log('Updated content:', updatedData);
} catch (error) {
console.error('Error:', error.message);
}
}
fileOperations();
Working with Directories
const fs = require('fs').promises;
const path = require('path');
async function directoryOperations() {
try {
// Create directory
await fs.mkdir('test-dir', { recursive: true });
console.log('Directory created');
// Read directory contents
const files = await fs.readdir('.');
console.log('Current directory files:', files);
// Create nested directories
await fs.mkdir('nested/deep/directory', { recursive: true });
// Copy file
await fs.copyFile('example.txt', 'test-dir/copied-file.txt');
// Rename/move file
await fs.rename('test-dir/copied-file.txt', 'test-dir/renamed-file.txt');
// Delete file
await fs.unlink('test-dir/renamed-file.txt');
// Remove directory
await fs.rmdir('test-dir');
} catch (error) {
console.error('Directory operation error:', error.message);
}
}
directoryOperations();
Streams for Large Files
const fs = require('fs');
const path = require('path');
// Reading large files with streams
function readLargeFile(filename) {
const readStream = fs.createReadStream(filename, { encoding: 'utf8' });
readStream.on('data', (chunk) => {
console.log('Received chunk of size:', chunk.length);
// Process chunk
});
readStream.on('end', () => {
console.log('Finished reading file');
});
readStream.on('error', (error) => {
console.error('Stream error:', error.message);
});
}
// Writing with streams
function writeWithStream(filename, data) {
const writeStream = fs.createWriteStream(filename);
writeStream.write(data);
writeStream.end();
writeStream.on('finish', () => {
console.log('Finished writing file');
});
writeStream.on('error', (error) => {
console.error('Write stream error:', error.message);
});
}
// Pipe streams (copy file)
function copyFileWithStreams(source, destination) {
const readStream = fs.createReadStream(source);
const writeStream = fs.createWriteStream(destination);
readStream.pipe(writeStream);
readStream.on('end', () => {
console.log('File copied successfully');
});
}
7. HTTP Module
Creating a Basic HTTP Server
const http = require('http');
const url = require('url');
// Create server
const server = http.createServer((req, res) => {
// Parse URL
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
// Set response headers
res.setHeader('Content-Type', 'text/html');
res.setHeader('Access-Control-Allow-Origin', '*');
// Route handling
if (path === '/' && method === 'GET') {
res.statusCode = 200;
res.end('
Welcome to Node.js Server! ');
} else if (path === '/about' && method === 'GET') {
res.statusCode = 200;
res.end('
About Page This is a Node.js server
');
} else if (path === '/api/users' && method === 'GET') {
res.setHeader('Content-Type', 'application/json');
res.statusCode = 200;
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
res.end(JSON.stringify(users));
} else {
res.statusCode = 404;
res.end('
404 - Page Not Found ');
}
});
// Start server
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Handling POST Requests
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
if (path === '/api/users' && method === 'POST') {
let body = '';
// Collect data chunks
req.on('data', (chunk) => {
body += chunk.toString();
});
// Process complete data
req.on('end', () => {
try {
const userData = JSON.parse(body);
console.log('Received user data:', userData);
// Simulate saving user
const newUser = {
id: Date.now(),
...userData,
createdAt: new Date().toISOString()
};
res.setHeader('Content-Type', 'application/json');
res.statusCode = 201;
res.end(JSON.stringify({
message: 'User created successfully',
user: newUser
}));
} catch (error) {
res.statusCode = 400;
res.end(JSON.stringify({ error: 'Invalid JSON' }));
}
});
} else {
res.statusCode = 404;
res.end(JSON.stringify({ error: 'Route not found' }));
}
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
Making HTTP Requests
const http = require('http');
const https = require('https');
// GET request
function makeGetRequest(url) {
const client = url.startsWith('https') ? https : http;
client.get(url, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Response:', JSON.parse(data));
});
}).on('error', (error) => {
console.error('Request error:', error.message);
});
}
// POST request
function makePostRequest(hostname, path, postData) {
const options = {
hostname: hostname,
port: 443,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('POST Response:', data);
});
});
req.on('error', (error) => {
console.error('POST Request error:', error.message);
});
req.write(postData);
req.end();
}
// Usage
makeGetRequest('https://jsonplaceholder.typicode.com/posts/1');
const postData = JSON.stringify({
title: 'My Post',
body: 'This is my post content',
userId: 1
});
makePostRequest('jsonplaceholder.typicode.com', '/posts', postData);
8. Express.js Framework
Getting Started with Express
# Install Express
npm install express
npm install -D nodemon
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies
// Basic routes
app.get('/', (req, res) => {
res.send('
Welcome to Express! ');
});
app.get('/api/users', (req, res) => {
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
res.json(users);
});
app.get('/api/users/:id', (req, res) => {
const userId = parseInt(req.params.id);
const user = { id: userId, name: 'John Doe', email: 'john@example.com' };
res.json(user);
});
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
const newUser = {
id: Date.now(),
name,
email,
createdAt: new Date().toISOString()
};
res.status(201).json(newUser);
});
app.listen(PORT, () => {
console.log(`Express server running on port ${PORT}`);
});
Express Middleware
const express = require('express');
const app = express();
// Built-in middleware
app.use(express.json());
app.use(express.static('public')); // Serve static files
// Custom middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // Call next middleware
});
// Authentication middleware
const authenticateToken = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
// Verify token (simplified)
if (token === 'Bearer valid-token') {
req.user = { id: 1, name: 'John Doe' };
next();
} else {
res.status(403).json({ error: 'Invalid token' });
}
};
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Protected route
app.get('/api/protected', authenticateToken, (req, res) => {
res.json({ message: 'This is protected data', user: req.user });
});
// 404 handler (should be last)
app.use('*', (req, res) => {
res.status(404).json({ error: 'Route not found' });
});
Express Router
// routes/users.js
const express = require('express');
const router = express.Router();
let users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
// GET /api/users
router.get('/', (req, res) => {
res.json(users);
});
// GET /api/users/:id
router.get('/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// POST /api/users
router.post('/', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'Name and email are required' });
}
const newUser = {
id: users.length + 1,
name,
email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT /api/users/:id
router.put('/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const { name, email } = req.body;
if (name) user.name = name;
if (email) user.email = email;
res.json(user);
});
// DELETE /api/users/:id
router.delete('/:id', (req, res) => {
const userIndex = users.findIndex(u => u.id === parseInt(req.params.id));
if (userIndex === -1) {
return res.status(404).json({ error: 'User not found' });
}
users.splice(userIndex, 1);
res.status(204).send();
});
module.exports = router;
// app.js
const express = require('express');
const userRoutes = require('./routes/users');
const app = express();
app.use(express.json());
app.use('/api/users', userRoutes);
app.listen(3000, () => {
console.log('Server running on port 3000');
});
🏋️ Exercise 2:
Create an Express API for a simple blog with routes for creating, reading, updating, and deleting blog posts. Include middleware for logging and error handling.
9. Database Integration
MongoDB with Mongoose
# Install MongoDB and Mongoose
npm install mongoose
const mongoose = require('mongoose');
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// Define schema
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
age: {
type: Number,
min: 0,
max: 120
},
createdAt: {
type: Date,
default: Date.now
}
});
// Create model
const User = mongoose.model('User', userSchema);
// CRUD operations
async function userOperations() {
try {
// Create user
const newUser = new User({
name: 'John Doe',
email: 'john@example.com',
age: 30
});
await newUser.save();
console.log('User created:', newUser);
// Find users
const users = await User.find();
console.log('All users:', users);
// Find one user
const user = await User.findOne({ email: 'john@example.com' });
console.log('Found user:', user);
// Update user
const updatedUser = await User.findByIdAndUpdate(
user._id,
{ age: 31 },
{ new: true }
);
console.log('Updated user:', updatedUser);
// Delete user
await User.findByIdAndDelete(user._id);
console.log('User deleted');
} catch (error) {
console.error('Database error:', error.message);
}
}
userOperations();
Express + MongoDB API
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/blog');
// Blog post schema
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
content: { type: String, required: true },
author: { type: String, required: true },
tags: [String],
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
const Post = mongoose.model('Post', postSchema);
// Routes
app.get('/api/posts', async (req, res) => {
try {
const posts = await Post.find().sort({ createdAt: -1 });
res.json(posts);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.get('/api/posts/:id', async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
res.json(post);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/posts', async (req, res) => {
try {
const post = new Post(req.body);
await post.save();
res.status(201).json(post);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.put('/api/posts/:id', async (req, res) => {
try {
const post = await Post.findByIdAndUpdate(
req.params.id,
{ ...req.body, updatedAt: new Date() },
{ new: true, runValidators: true }
);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
res.json(post);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.delete('/api/posts/:id', async (req, res) => {
try {
const post = await Post.findByIdAndDelete(req.params.id);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
res.status(204).send();
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => {
console.log('Blog API running on port 3000');
});
Environment Variables
// Install dotenv
// npm install dotenv
// .env file
NODE_ENV=development
PORT=3000
MONGODB_URI=mongodb://localhost:27017/myapp
JWT_SECRET=your-secret-key
API_KEY=your-api-key
// app.js
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// Use environment variables
const PORT = process.env.PORT || 3000;
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/defaultdb';
mongoose.connect(MONGODB_URI);
app.get('/', (req, res) => {
res.json({
environment: process.env.NODE_ENV,
port: PORT,
message: 'Environment variables loaded!'
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
10. Practice Projects
Project 1: RESTful API with Authentication
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
require('dotenv').config();
const app = express();
app.use(express.json());
// User schema
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
createdAt: { type: Date, default: Date.now }
});
// Hash password before saving
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 10);
next();
});
const User = mongoose.model('User', userSchema);
// Middleware to verify JWT
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
// Register route
app.post('/api/register', async (req, res) => {
try {
const { username, email, password } = req.body;
// Check if user exists
const existingUser = await User.findOne({
$or: [{ email }, { username }]
});
if (existingUser) {
return res.status(400).json({ error: 'User already exists' });
}
// Create user
const user = new User({ username, email, password });
await user.save();
// Generate token
const token = jwt.sign(
{ userId: user._id, username: user.username },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
res.status(201).json({
message: 'User registered successfully',
token,
user: {
id: user._id,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Login route
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Check password
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate token
const token = jwt.sign(
{ userId: user._id, username: user.username },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
res.json({
message: 'Login successful',
token,
user: {
id: user._id,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Protected route
app.get('/api/profile', authenticateToken, async (req, res) => {
try {
const user = await User.findById(req.user.userId).select('-password');
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
mongoose.connect(process.env.MONGODB_URI);
app.listen(process.env.PORT, () => {
console.log(`Auth API running on port ${process.env.PORT}`);
});
Project 2: Real-time Chat Application
// Install: npm install socket.io
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
// Serve static files
app.use(express.static('public'));
// Store connected users
const users = new Map();
// Socket.io connection handling
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
// Handle user joining
socket.on('join', (username) => {
users.set(socket.id, username);
socket.broadcast.emit('user-joined', username);
// Send current users list
io.emit('users-list', Array.from(users.values()));
});
// Handle messages
socket.on('message', (data) => {
const username = users.get(socket.id);
const messageData = {
username,
message: data.message,
timestamp: new Date().toISOString()
};
// Broadcast message to all clients
io.emit('message', messageData);
});
// Handle typing indicator
socket.on('typing', () => {
const username = users.get(socket.id);
socket.broadcast.emit('typing', username);
});
socket.on('stop-typing', () => {
socket.broadcast.emit('stop-typing');
});
// Handle disconnection
socket.on('disconnect', () => {
const username = users.get(socket.id);
users.delete(socket.id);
if (username) {
socket.broadcast.emit('user-left', username);
io.emit('users-list', Array.from(users.values()));
}
console.log('User disconnected:', socket.id);
});
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Chat server running on port ${PORT}`);
});
// public/index.html (basic chat interface)
/*
Node.js Chat
*/
🏋️ Project Ideas:
Build these projects to master Node.js:
Task Management API: CRUD operations with user authentication
File Upload Service: Handle file uploads with multer
URL Shortener: Create short URLs like bit.ly
Weather API: Fetch and cache weather data
Blog Platform: Full-featured blog with comments
E-commerce API: Products, orders, and payments
Real-time Notifications: WebSocket-based notifications
GraphQL API: Modern API with GraphQL
Next Steps
Advanced Node.js Topics:
Testing: Jest, Mocha, Supertest
Security: Helmet, rate limiting, input validation
Performance: Clustering, caching, optimization
Deployment: Docker, PM2, cloud platforms
Microservices: Service architecture patterns
GraphQL: Apollo Server, schema design
TypeScript: Type-safe Node.js development
Monitoring: Logging, metrics, error tracking
🎉 Congratulations!
You've mastered Node.js fundamentals! You can now build scalable server-side applications and APIs.
Keep building projects and exploring the Node.js ecosystem!