🖥️ Backend Development Course

🎯 Learning Objectives

After completing this course, you will be able to:

⚡ Prerequisites

  • Strong JavaScript knowledge
  • Understanding of HTTP protocol
  • Basic command line skills
  • Node.js and npm installed
  • Database basics (SQL/NoSQL)

1. Introduction to Backend Development

What is Backend Development?

Backend development involves server-side logic, databases, and APIs that power web applications.

  • Server: Handles requests and responses
  • Database: Stores and retrieves data
  • API: Interface for frontend communication
  • Business Logic: Core application functionality

Backend Responsibilities

  • Data processing and validation
  • User authentication and authorization
  • Database operations (CRUD)
  • API endpoint creation
  • File handling and storage
  • Email and notifications
  • Security implementation

2. Node.js & Express

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 engine that allows you to run JavaScript on the server.

Basic Express Server

// server.js const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Routes app.get('/', (req, res) => { res.json({ message: 'Welcome to the API' }); }); app.get('/api/users', (req, res) => { const users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' } ]; res.json(users); }); app.post('/api/users', (req, res) => { const { name, email } = req.body; const newUser = { id: Date.now(), name, email }; res.status(201).json(newUser); }); // Start server app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });

Express Router

// routes/users.js const express = require('express'); const router = express.Router(); // GET all users router.get('/', async (req, res) => { try { const users = await User.find(); res.json(users); } catch (error) { res.status(500).json({ error: error.message }); } }); // GET user by ID router.get('/:id', async (req, res) => { try { const user = await User.findById(req.params.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); } catch (error) { res.status(500).json({ error: error.message }); } }); // POST create user router.post('/', async (req, res) => { try { const user = new User(req.body); await user.save(); res.status(201).json(user); } catch (error) { res.status(400).json({ error: error.message }); } }); // PUT update user router.put('/:id', async (req, res) => { try { const user = await User.findByIdAndUpdate( req.params.id, req.body, { new: true, runValidators: true } ); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); } catch (error) { res.status(400).json({ error: error.message }); } }); // DELETE user router.delete('/:id', async (req, res) => { try { const user = await User.findByIdAndDelete(req.params.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json({ message: 'User deleted successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router; // In server.js const userRoutes = require('./routes/users'); app.use('/api/users', userRoutes);

3. Database Integration

MongoDB with Mongoose

// Install: npm install mongoose const mongoose = require('mongoose'); // Connect to MongoDB mongoose.connect('mongodb://localhost:27017/myapp', { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('MongoDB connected')) .catch(err => console.error('MongoDB connection error:', err)); // Define Schema const userSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Name is required'], trim: true, minlength: 2, maxlength: 50 }, email: { type: String, required: [true, 'Email is required'], unique: true, lowercase: true, match: [/^\S+@\S+\.\S+$/, 'Please enter a valid email'] }, password: { type: String, required: [true, 'Password is required'], minlength: 6 }, role: { type: String, enum: ['user', 'admin'], default: 'user' }, createdAt: { type: Date, default: Date.now } }); // Create Model const User = mongoose.model('User', userSchema); // CRUD Operations // Create const newUser = new User({ name: 'John Doe', email: 'john@example.com', password: 'hashedpassword' }); await newUser.save(); // Read const users = await User.find(); const user = await User.findById(userId); const userByEmail = await User.findOne({ email: 'john@example.com' }); // Update await User.findByIdAndUpdate(userId, { name: 'Jane Doe' }); await User.updateOne({ email: 'john@example.com' }, { role: 'admin' }); // Delete await User.findByIdAndDelete(userId); await User.deleteOne({ email: 'john@example.com' });

PostgreSQL with Sequelize

// Install: npm install sequelize pg pg-hstore const { Sequelize, DataTypes } = require('sequelize'); // Connect to PostgreSQL const sequelize = new Sequelize('database', 'username', 'password', { host: 'localhost', dialect: 'postgres' }); // Test connection sequelize.authenticate() .then(() => console.log('PostgreSQL connected')) .catch(err => console.error('Connection error:', err)); // Define Model const User = sequelize.define('User', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, name: { type: DataTypes.STRING, allowNull: false, validate: { len: [2, 50] } }, email: { type: DataTypes.STRING, allowNull: false, unique: true, validate: { isEmail: true } }, password: { type: DataTypes.STRING, allowNull: false }, role: { type: DataTypes.ENUM('user', 'admin'), defaultValue: 'user' } }); // Sync database await sequelize.sync(); // CRUD Operations // Create const user = await User.create({ name: 'John Doe', email: 'john@example.com', password: 'hashedpassword' }); // Read const users = await User.findAll(); const user = await User.findByPk(userId); const userByEmail = await User.findOne({ where: { email: 'john@example.com' } }); // Update await User.update( { name: 'Jane Doe' }, { where: { id: userId } } ); // Delete await User.destroy({ where: { id: userId } });

4. Authentication & Authorization

JWT Authentication

// Install: npm install bcryptjs jsonwebtoken const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); // Register User app.post('/api/auth/register', async (req, res) => { try { const { name, email, password } = req.body; // Check if user exists const existingUser = await User.findOne({ email }); if (existingUser) { return res.status(400).json({ error: 'User already exists' }); } // Hash password const salt = await bcrypt.genSalt(10); const hashedPassword = await bcrypt.hash(password, salt); // Create user const user = new User({ name, email, password: hashedPassword }); await user.save(); // Generate token const token = jwt.sign( { userId: user._id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '7d' } ); res.status(201).json({ message: 'User registered successfully', token, user: { id: user._id, name: user.name, email: user.email } }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Login User app.post('/api/auth/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 isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate token const token = jwt.sign( { userId: user._id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '7d' } ); res.json({ message: 'Login successful', token, user: { id: user._id, name: user.name, email: user.email } }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Authentication Middleware const authenticate = async (req, res, next) => { try { const token = req.header('Authorization')?.replace('Bearer ', ''); if (!token) { return res.status(401).json({ error: 'No token provided' }); } const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = await User.findById(decoded.userId); if (!user) { return res.status(401).json({ error: 'User not found' }); } req.user = user; next(); } catch (error) { res.status(401).json({ error: 'Invalid token' }); } }; // Protected Route app.get('/api/profile', authenticate, (req, res) => { res.json({ user: { id: req.user._id, name: req.user.name, email: req.user.email } }); });

5. Middleware

Custom Middleware

// Logging Middleware const logger = (req, res, next) => { console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`); next(); }; // Error Handling Middleware const errorHandler = (err, req, res, next) => { console.error(err.stack); res.status(err.status || 500).json({ error: { message: err.message || 'Internal Server Error', status: err.status || 500 } }); }; // Validation Middleware const validateUser = (req, res, next) => { const { name, email, password } = req.body; if (!name || !email || !password) { return res.status(400).json({ error: 'Name, email, and password are required' }); } if (password.length < 6) { return res.status(400).json({ error: 'Password must be at least 6 characters' }); } next(); }; // Rate Limiting Middleware const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs message: 'Too many requests, please try again later' }); // CORS Middleware const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', credentials: true })); // Apply Middleware app.use(logger); app.use('/api/', limiter); app.post('/api/users', validateUser, createUser); app.use(errorHandler);

6. Security Best Practices

🔒 Security Essentials

Security Implementation

// Install security packages // npm install helmet express-mongo-sanitize xss-clean express-rate-limit const helmet = require('helmet'); const mongoSanitize = require('express-mongo-sanitize'); const xss = require('xss-clean'); const rateLimit = require('express-rate-limit'); // Helmet - Set security HTTP headers app.use(helmet()); // Data sanitization against NoSQL query injection app.use(mongoSanitize()); // Data sanitization against XSS app.use(xss()); // Rate limiting const limiter = rateLimit({ max: 100, windowMs: 60 * 60 * 1000, message: 'Too many requests from this IP' }); app.use('/api', limiter); // Environment variables require('dotenv').config(); const config = { port: process.env.PORT || 3000, dbUrl: process.env.DATABASE_URL, jwtSecret: process.env.JWT_SECRET, nodeEnv: process.env.NODE_ENV };

7. Deployment

Deployment Checklist

// package.json scripts { "scripts": { "start": "node server.js", "dev": "nodemon server.js", "test": "jest", "build": "npm run test" } } // .env.example (commit this, not .env) PORT=3000 DATABASE_URL=your_database_url JWT_SECRET=your_jwt_secret NODE_ENV=production // .gitignore node_modules/ .env *.log .DS_Store // Procfile (for Heroku) web: node server.js // Docker FROM node:16 WORKDIR /app COPY package*.json ./ RUN npm install --production COPY . . EXPOSE 3000 CMD ["npm", "start"]

Practice Exercises

📝 Exercise 1: Build a Blog API (4 points)

Create a RESTful API for a blog with:

📝 Exercise 2: File Upload Service (3 points)

Implement file upload functionality:

📝 Exercise 3: Real-time Chat API (3 points)

Build a real-time chat system:

🎉 Summary

You've completed the Backend Development course! You now know:

Total points available: 10/10

⬅️ Previous

Course 5: CSS Frameworks

➡️ Next

Course 7: REST APIs