Backend Developer Guide
Comprehensive technical reference with practical examples and implementation guides
HTTP Methods & Status Codes
HTTP Methods
| Method | Purpose | Idempotent | Example Use |
|---|---|---|---|
GET | Retrieve resource | ✓ | Get user list |
POST | Create resource | ✗ | Create new user |
PUT | Replace resource | ✓ | Update full user |
PATCH | Partial update | ✗ | Update user email |
DELETE | Remove resource | ✓ | Delete user |
Express.js API
// RESTful API Implementation
router.get('/users', async (req, res) => {
const users = await User.find();
res.json(users);
});
router.post('/users', async (req, res) => {
const user = await User.create(req.body);
res.status(201).location(\`/users/\${user.id}\`).json(user);
});
router.patch('/users/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(req.params.id, { $set: req.body }, { new: true });
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
});
HTTP Status Codes
| Code | Meaning | When to Use |
|---|---|---|
200 | OK | Successful GET, PUT, PATCH |
201 | Created | Successful POST with new resource |
204 | No Content | Successful DELETE |
400 | Bad Request | Invalid request body/params |
401 | Unauthorized | Missing/invalid authentication |
403 | Forbidden | Authenticated but no permission |
404 | Not Found | Resource doesn't exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
Authentication: OAuth, OIDC, JWT & Sessions
OAuth 2.0 vs OpenID Connect
| Aspect | OAuth 2.0 | OpenID Connect (OIDC) |
|---|---|---|
| Purpose | Authorization (access) | Authentication (identity) |
| Token | Access Token | ID Token (JWT) + Access Token |
| User Info | No | Yes (profile, email, etc) |
| Use Case | API access delegation | Single Sign-On (SSO) |
JWT vs Sessions
JWT (Stateless)
- Self-contained tokens
- No server storage
- Scales easily horizontally
- Can't revoke before expiry
- Larger payload
Sessions (Stateful)
- Session ID in cookie
- Requires Redis/DB storage
- Needs sticky sessions
- Instant revocation
- Smaller cookie
JWT Implementation
const jwt = require('jsonwebtoken');
// Generate JWT
function generateToken(userId) {
return jwt.sign(
{ userId, type: 'access' },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
}
// Verify middleware
function auth(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'No token' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId;
next();
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
}
📚 References
Security: Hashing, Encryption & Rate Limiting
Password Hashing with Bcrypt
Node.js
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;
// Hash password
async function hashPassword(password) {
return await bcrypt.hash(password, SALT_ROUNDS);
}
// Verify password
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// Registration
router.post('/register', async (req, res) => {
const hashedPassword = await hashPassword(req.body.password);
const user = await User.create({ ...req.body, password: hashedPassword });
res.status(201).json({ id: user.id });
});
Encryption Standards
AES-256 Encryption
const crypto = require('crypto');
// Encrypt data
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(key, 'hex'), iv);
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
const authTag = cipher.getAuthTag();
return { iv: iv.toString('hex'), data: encrypted.toString('hex'), authTag: authTag.toString('hex') };
}
// Decrypt data
function decrypt(encrypted, key) {
const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key, 'hex'), Buffer.from(encrypted.iv, 'hex'));
decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));
const decrypted = Buffer.concat([decipher.update(Buffer.from(encrypted.data, 'hex')), decipher.final()]);
return decrypted.toString('utf8');
}
Rate Limiting & DDoS Protection
Express Rate Limit
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const redis = require('redis');
const limiter = rateLimit({
store: new RedisStore({ client: redis.createClient() }),
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
📚 References
WebSockets & Real-time Communication
WebSockets provide full-duplex communication channels over a single TCP connection, enabling real-time data transfer.
Socket.io Server
const io = require('socket.io')(server, {
cors: { origin: '*' }
});
io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
// Join room
socket.on('join', (room) => {
socket.join(room);
socket.to(room).emit('user-joined', socket.id);
});
// Broadcast message
socket.on('message', (data) => {
io.to(data.room).emit('message', {
user: socket.id,
text: data.text,
timestamp: Date.now()
});
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
Client Implementation
const socket = io('http://localhost:3000');
socket.on('connect', () => {
console.log('Connected to server');
socket.emit('join', 'room1');
});
socket.on('message', (data) => {
console.log('New message:', data);
});
function sendMessage(text) {
socket.emit('message', { room: 'room1', text });
}
📚 References
Databases: SQL, NoSQL, ACID & Optimization
SQL vs NoSQL
| Feature | SQL (PostgreSQL, MySQL) | NoSQL (MongoDB, Cassandra) |
|---|---|---|
| Schema | Fixed schema, tables | Flexible schema, documents |
| Scalability | Vertical (scale up) | Horizontal (scale out) |
| ACID | Full ACID compliance | Eventually consistent |
| Joins | Complex joins supported | No joins (denormalized) |
| Use Case | Structured data, transactions | Flexible data, high throughput |
ACID Properties
- Atomicity: All operations succeed or all fail
- Consistency: Database remains in valid state
- Isolation: Concurrent transactions don't interfere
- Durability: Committed data persists permanently
PostgreSQL Transaction
-- Bank transfer example
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- Only commits if both succeed
COMMIT;
Indexing Strategies
Index Types
-- B-Tree index (default, good for =, <, >, <=, >=)
CREATE INDEX idx_users_email ON users(email);
-- Unique index
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
-- Composite index
CREATE INDEX idx_users_name_age ON users(last_name, first_name, age);
-- Partial index
CREATE INDEX idx_active_users ON users(email) WHERE status = 'active';
-- Full-text search
CREATE INDEX idx_posts_content ON posts USING gin(to_tsvector('english', content));
Query Optimization
Optimization Techniques
-- Use EXPLAIN to analyze query
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 5;
-- Optimize with proper indexes
CREATE INDEX idx_users_created ON users(created_at);
CREATE INDEX idx_orders_user ON orders(user_id);
-- Avoid SELECT *, specify columns
SELECT id, name, email FROM users;
-- Use LIMIT for pagination
SELECT * FROM users ORDER BY created_at DESC LIMIT 10 OFFSET 20;
Normalization vs Denormalization
| Aspect | Normalization | Denormalization |
|---|---|---|
| Redundancy | Minimal | Intentional duplication |
| Writes | Fast (single location) | Slower (multiple updates) |
| Reads | Slower (requires joins) | Faster (pre-joined) |
| Storage | Efficient | More space needed |
| Use When | Write-heavy, consistency critical | Read-heavy, performance critical |
📚 References
System Design & Architecture
Monolith vs Microservices
| Aspect | Monolith | Microservices |
|---|---|---|
| Structure | Single deployable unit | Multiple independent services |
| Deployment | Deploy entire app | Deploy services independently |
| Scalability | Scale entire app | Scale services individually |
| Complexity | Simpler initially | Complex infrastructure |
| Technology | Single stack | Polyglot (different tech per service) |
| Best For | Small teams, MVPs | Large teams, complex systems |
Load Balancing
Nginx Load Balancer
http {
upstream backend {
least_conn; # Load balancing algorithm
server backend1.example.com:3000 weight=3;
server backend2.example.com:3000 weight=2;
server backend3.example.com:3000 backup;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
Caching Strategies
Redis Caching
const redis = require('redis');
const client = redis.createClient();
// Cache-aside pattern
async function getUser(id) {
// Try cache first
const cached = await client.get(\`user:\${id}\`);
if (cached) return JSON.parse(cached);
// Cache miss: fetch from DB
const user = await User.findById(id);
// Store in cache
await client.setex(\`user:\${id}\`, 3600, JSON.stringify(user));
return user;
}
// Cache invalidation
async function updateUser(id, data) {
const user = await User.findByIdAndUpdate(id, data);
await client.del(\`user:\${id}\`); // Invalidate cache
return user;
}
Message Brokers: Kafka vs RabbitMQ
| Feature | Kafka | RabbitMQ |
|---|---|---|
| Model | Pub/Sub, Log-based | Queue-based, Routing |
| Throughput | Very high (millions/sec) | High (tens of thousands/sec) |
| Ordering | Guaranteed per partition | Per queue |
| Retention | Configurable (days/weeks) | Transient (consumed once) |
| Use Case | Event streaming, logs | Task queues, RPC |
DevOps: Docker, CI/CD, Linux
Docker Containerization
Dockerfile
# Multi-stage build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=postgres
depends_on:
- postgres
- redis
postgres:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
pgdata:
CI/CD Pipeline
GitHub Actions
name: CI/CD Pipeline
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm test
- run: npm run lint
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:latest .
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push myapp:latest
- name: Deploy to production
run: kubectl apply -f k8s/
Linux Command Line Essentials
Bash
# Process management
ps aux | grep node
kill -9
top / htop
# Logs
tail -f /var/log/app.log
grep "ERROR" app.log | wc -l
journalctl -u myservice -f
# Networking
netstat -tulpn
curl -X POST http://api.example.com/users -d '{"name":"John"}'
wget https://example.com/file.zip
# File operations
find /var/log -name "*.log" -mtime +7 -delete
du -sh /var/lib/docker
tar -czf backup.tar.gz /data/
# Permissions
chmod 755 script.sh
chown www-data:www-data /var/www/html
# Bash scripting
#!/bin/bash
for i in {1..5}; do
echo "Iteration $i"
curl http://localhost:3000/health
sleep 5
done
Cloud Services (AWS/GCP/Azure)
| Service Type | AWS | GCP | Azure |
|---|---|---|---|
| Compute | EC2, Lambda | Compute Engine, Cloud Functions | VM, Functions |
| Storage | S3, EBS | Cloud Storage, Persistent Disk | Blob Storage |
| Database | RDS, DynamoDB | Cloud SQL, Firestore | SQL Database, Cosmos DB |
| Containers | ECS, EKS | GKE | AKS |
| CDN | CloudFront | Cloud CDN | Azure CDN |
📚 References
Scalability & Performance
Vertical vs Horizontal Scaling
| Aspect | Vertical (Scale Up) | Horizontal (Scale Out) |
|---|---|---|
| Method | Increase server resources | Add more servers |
| Limit | Hardware maximum | Nearly unlimited |
| Cost | Expensive at scale | Cost-effective |
| Downtime | Required for upgrades | Zero downtime |
| Complexity | Simple | Requires load balancing |
Database Sharding
Sharding Strategy
// Hash-based sharding
function getShardId(userId, numShards) {
const hash = crypto.createHash('md5').update(userId.toString()).digest('hex');
return parseInt(hash, 16) % numShards;
}
// Route to correct shard
function getUserDatabase(userId) {
const shardId = getShardId(userId, 4);
return databases[shardId];
}
// Example usage
const user = await getUserDatabase(userId).findOne({ id: userId });
Database Replication
Master-Replica Setup
// Configure read/write splitting
const masterDb = new Sequelize('postgres://master:5432/db');
const replicaDb = new Sequelize('postgres://replica:5432/db');
// Write to master
async function createUser(data) {
return await masterDb.models.User.create(data);
}
// Read from replica
async function getUsers() {
return await replicaDb.models.User.findAll();
}
Connection Pooling
PostgreSQL Pool
const { Pool } = require('pg');
const pool = new Pool({
host: 'localhost',
port: 5432,
database: 'mydb',
user: 'postgres',
password: 'secret',
max: 20, // Max connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
// Use pool for queries
async function query(sql, params) {
const client = await pool.connect();
try {
const result = await client.query(sql, params);
return result.rows;
} finally {
client.release();
}
}
📚 References
Testing, Logging & Monitoring
Testing Pyramid
Unit Tests (Jest)
describe('UserService', () => {
test('should create user with hashed password', async () => {
const userData = { email: 'test@example.com', password: 'secret123' };
const user = await UserService.create(userData);
expect(user.email).toBe(userData.email);
expect(user.password).not.toBe(userData.password);
expect(await bcrypt.compare(userData.password, user.password)).toBe(true);
});
});
Integration Tests
const request = require('supertest');
const app = require('../app');
describe('POST /api/users', () => {
test('should create user and return 201', async () => {
const res = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', password: 'secret123' });
expect(res.status).toBe(201);
expect(res.body).toHaveProperty('id');
expect(res.body.email).toBe('test@example.com');
});
});
Load Testing (k6)
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 100, // 100 virtual users
duration: '30s', // Test duration
};
export default function() {
const res = http.get('http://api.example.com/users');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
sleep(1);
}
Structured Logging
Winston Logger
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// Usage
logger.info('User created', { userId: 123, email: 'user@example.com' });
logger.error('Database connection failed', { error: err.message, stack: err.stack });
Monitoring with Prometheus
Prometheus Metrics
const client = require('prom-client');
// Create metrics
const httpRequestDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code']
});
const activeConnections = new client.Gauge({
name: 'active_connections',
help: 'Number of active connections'
});
// Middleware
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration.labels(req.method, req.route.path, res.statusCode).observe(duration);
});
next();
});
// Metrics endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', client.register.contentType);
res.end(await client.register.metrics());
});
Distributed Tracing
OpenTelemetry
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const provider = new NodeTracerProvider();
const exporter = new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces' });
provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.register();
// Create spans
const tracer = provider.getTracer('my-service');
const span = tracer.startSpan('database-query');
// ... do work
span.end();
✨ Complete Backend Developer Reference - Updated 2026
For questions or contributions: GitHub