Skip to content

tusshaarpd/API-Integration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Complete API Integration Guide

A comprehensive guide to building, integrating, and deploying REST APIs with authentication, database connectivity, and external service integration. Suitable for beginners to advanced developers.

Table of Contents


1. Introduction to APIs

What is an API?

An API (Application Programming Interface) is a set of rules and protocols that allows different software applications to communicate with each other. It defines the methods and data formats that applications can use to request and exchange information.

Think of it like a waiter in a restaurant:

  • Customer = Client Application
  • Waiter = API
  • Kitchen = Server/Backend
  • Dish = Response/Data

The customer doesn't need to know how the kitchen works; the waiter handles the communication.

Types of APIs

1. REST APIs (Representational State Transfer)

  • Uses HTTP methods (GET, POST, PUT, DELETE, PATCH)
  • Stateless architecture
  • Easy to understand and implement
  • Returns JSON or XML
  • Most popular for web applications

Example:

GET /api/users          → Fetch all users
POST /api/users         → Create new user
GET /api/users/1        → Fetch user with ID 1
PUT /api/users/1        → Update user with ID 1
DELETE /api/users/1     → Delete user with ID 1

2. SOAP APIs (Simple Object Access Protocol)

  • Protocol-heavy, uses XML
  • More complex and structured
  • Better for enterprise systems
  • Slower than REST
  • Less commonly used in modern development

3. GraphQL APIs

  • Query language for APIs
  • Request only the data you need
  • Single endpoint for all queries
  • Reduces over-fetching of data
  • Growing in popularity

Example GraphQL Query:

query {
  user(id: 1) {
    name
    email
    posts {
      title
    }
  }
}

HTTP Methods Explained

Method Purpose Safe Idempotent Body
GET Retrieve data Yes Yes No
POST Create new resource No No Yes
PUT Replace entire resource No Yes Yes
PATCH Partially update resource No No Yes
DELETE Delete resource No Yes No
HEAD Like GET but without response body Yes Yes No

Key Terms:

  • Safe: Method doesn't modify data
  • Idempotent: Multiple identical requests = single request

HTTP Status Codes Explained

2xx - Success

Code Meaning
200 OK - Request successful
201 Created - Resource created successfully
204 No Content - Successful but no content to return

3xx - Redirection

Code Meaning
301 Moved Permanently
302 Found (Temporary redirect)
304 Not Modified

4xx - Client Error

Code Meaning
400 Bad Request - Invalid syntax
401 Unauthorized - Authentication required
403 Forbidden - Authenticated but no permission
404 Not Found - Resource doesn't exist
429 Too Many Requests - Rate limited

5xx - Server Error

Code Meaning
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable

JSON Structure Basics

JSON (JavaScript Object Notation) is the standard format for API responses.

{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "isActive": true,
  "age": null,
  "roles": ["admin", "user"],
  "metadata": {
    "createdAt": "2024-01-15",
    "lastLogin": "2024-02-16"
  }
}

JSON Data Types:

  • string - Text enclosed in quotes
  • number - Integer or decimal
  • boolean - true or false
  • null - Empty/no value
  • array - List of items []
  • object - Key-value pairs {}

Authentication Types

1. API Key Authentication

Simple but less secure. Key sent with each request.

headers: {
  "Authorization": "Bearer YOUR_API_KEY"
}

Use Case: Public APIs, internal services

Pros: Simple, lightweight Cons: Less secure, key exposed if leaked

2. JWT (JSON Web Token) Authentication

Industry standard. Token contains encoded claims.

Structure: header.payload.signature

Example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Use Case: Modern web applications, microservices

Pros: Stateless, scalable, includes claims Cons: Token size, can't revoke immediately

3. OAuth 2.0 Authentication

Third-party authentication. User grants permission to access resources.

1. User clicks "Login with Google"
2. Redirected to Google login
3. Google returns authorization code
4. App exchanges code for access token
5. App uses token to access user data

Use Case: Social login, delegated access

Pros: Secure, user doesn't share password, granular permissions Cons: Complex implementation, external dependency


2. Setting Up Backend API with Node.js & Express

Project Structure

backend/
├── server.js                 # Entry point
├── package.json             # Dependencies
├── .env                     # Environment variables (local)
├── .env.example            # Example env file
├── routes/
│   ├── users.js            # User routes
│   └── auth.js             # Auth routes
├── controllers/
│   ├── userController.js   # User logic
│   └── authController.js   # Auth logic
├── middleware/
│   ├── auth.js             # JWT verification
│   ├── errorHandler.js     # Error handling
│   └── rateLimiter.js      # Rate limiting
├── models/
│   └── User.js             # Data model
├── config/
│   └── db.js               # Database config
└── utils/
    └── logger.js           # Logging utility

Installing Dependencies

# Initialize Node project
npm init -y

# Install dependencies
npm install express dotenv jsonwebtoken bcrypt cors axios
npm install --save-dev nodemon

# Or install from package.json
npm install

Basic Express Server

Create server.js:

const express = require("express");
const dotenv = require("dotenv");
const cors = require("cors");
const errorHandler = require("./middleware/errorHandler");

// Load environment variables
dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// ============ MIDDLEWARE ============
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

// ============ ROUTES ============
app.get("/", (req, res) => {
  res.json({
    message: "Welcome to API Integration Guide",
    version: "1.0.0",
    endpoints: {
      users: "/api/v1/users",
      auth: "/api/v1/auth"
    }
  });
});

app.get("/api/users", (req, res) => {
  res.status(200).json({
    message: "Users fetched successfully",
    users: [
      { id: 1, name: "John Doe", email: "john@example.com" },
      { id: 2, name: "Jane Smith", email: "jane@example.com" }
    ]
  });
});

// Health check endpoint
app.get("/health", (req, res) => {
  res.status(200).json({ status: "Server is running" });
});

// 404 handler
app.use((req, res) => {
  res.status(404).json({ error: "Route not found" });
});

// Error handling middleware
app.use(errorHandler);

// ============ START SERVER ============
app.listen(PORT, () => {
  console.log(`✓ Server running on http://localhost:${PORT}`);
});

module.exports = app;

CRUD Operations Example

Create controllers/userController.js:

// In-memory database (replace with real DB)
let users = [
  { id: 1, name: "John Doe", email: "john@example.com", createdAt: new Date() },
  { id: 2, name: "Jane Smith", email: "jane@example.com", createdAt: new Date() }
];

let nextId = 3;

// GET all users
exports.getAllUsers = (req, res) => {
  const { page = 1, limit = 10 } = req.query;

  const startIndex = (page - 1) * limit;
  const paginatedUsers = users.slice(startIndex, startIndex + parseInt(limit));

  res.status(200).json({
    data: paginatedUsers,
    total: users.length,
    page: parseInt(page),
    limit: parseInt(limit)
  });
};

// GET single user
exports.getUserById = (req, res) => {
  const { id } = req.params;
  const user = users.find(u => u.id === parseInt(id));

  if (!user) {
    return res.status(404).json({ error: "User not found" });
  }

  res.status(200).json({ data: user });
};

// CREATE user
exports.createUser = (req, res) => {
  const { name, email } = req.body;

  // Validation
  if (!name || !email) {
    return res.status(400).json({
      error: "Name and email are required"
    });
  }

  // Check if email exists
  if (users.some(u => u.email === email)) {
    return res.status(409).json({
      error: "Email already exists"
    });
  }

  const newUser = {
    id: nextId++,
    name,
    email,
    createdAt: new Date()
  };

  users.push(newUser);

  res.status(201).json({
    message: "User created successfully",
    data: newUser
  });
};

// UPDATE user
exports.updateUser = (req, res) => {
  const { id } = req.params;
  const { name, email } = req.body;

  const user = users.find(u => u.id === parseInt(id));

  if (!user) {
    return res.status(404).json({ error: "User not found" });
  }

  // Update only provided fields
  if (name) user.name = name;
  if (email) user.email = email;
  user.updatedAt = new Date();

  res.status(200).json({
    message: "User updated successfully",
    data: user
  });
};

// DELETE user
exports.deleteUser = (req, res) => {
  const { id } = req.params;

  const index = users.findIndex(u => u.id === parseInt(id));

  if (index === -1) {
    return res.status(404).json({ error: "User not found" });
  }

  const deletedUser = users.splice(index, 1);

  res.status(200).json({
    message: "User deleted successfully",
    data: deletedUser[0]
  });
};

Create routes/users.js:

const express = require("express");
const userController = require("../controllers/userController");
const auth = require("../middleware/auth");

const router = express.Router();

// Public routes
router.get("/", userController.getAllUsers);
router.get("/:id", userController.getUserById);

// Protected routes (require authentication)
router.post("/", auth, userController.createUser);
router.put("/:id", auth, userController.updateUser);
router.delete("/:id", auth, userController.deleteUser);

module.exports = router;

Update server.js to include routes:

const userRoutes = require("./routes/users");

// After other middleware
app.use("/api/v1/users", userRoutes);

Middleware Examples

Create middleware/auth.js:

const jwt = require("jsonwebtoken");

const auth = (req, res, next) => {
  try {
    const token = req.headers.authorization?.split(" ")[1];

    if (!token) {
      return res.status(401).json({ error: "No token provided" });
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    res.status(401).json({ error: "Invalid token" });
  }
};

module.exports = auth;

Create middleware/errorHandler.js:

const errorHandler = (err, req, res, next) => {
  console.error(err.stack);

  res.status(err.status || 500).json({
    error: err.message || "Internal Server Error",
    status: err.status || 500
  });
};

module.exports = errorHandler;

Create middleware/rateLimiter.js:

const rateLimit = require("express-rate-limit");

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Max 100 requests per windowMs
  message: "Too many requests, please try again later",
  standardHeaders: true,
  legacyHeaders: false
});

module.exports = limiter;

Error Handling

Best practice error handling in controllers:

exports.createUser = async (req, res, next) => {
  try {
    const { name, email } = req.body;

    // Validation
    if (!name || !email) {
      const error = new Error("Name and email are required");
      error.status = 400;
      throw error;
    }

    // Database operation
    const newUser = await User.create({ name, email });

    res.status(201).json({
      message: "User created",
      data: newUser
    });
  } catch (error) {
    next(error); // Pass to error handler middleware
  }
};

Environment Variables

Create .env:

PORT=3000
NODE_ENV=development

# Database
DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=yourpassword
DB_NAME=api_db

# JWT
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production
JWT_EXPIRE=7d

# External APIs
WEATHER_API_KEY=your_weather_api_key
EXTERNAL_API_URL=https://api.example.com

# Logging
LOG_LEVEL=debug

Create .env.example (commit this, not .env):

PORT=3000
NODE_ENV=development
DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=
DB_NAME=api_db
JWT_SECRET=
JWT_EXPIRE=7d
WEATHER_API_KEY=
EXTERNAL_API_URL=
LOG_LEVEL=debug

Access in code:

const PORT = process.env.PORT || 3000;
const JWT_SECRET = process.env.JWT_SECRET;
const NODE_ENV = process.env.NODE_ENV;

JWT Authentication Example

Create controllers/authController.js:

const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");

// Simulated database
const users = [
  {
    id: 1,
    email: "user@example.com",
    password: "$2b$10$..." // bcrypt hashed
  }
];

exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Validate input
    if (!email || !password) {
      return res.status(400).json({ error: "Email and password required" });
    }

    // Find user
    const user = users.find(u => u.email === email);
    if (!user) {
      return res.status(401).json({ error: "Invalid credentials" });
    }

    // Verify password
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(401).json({ error: "Invalid credentials" });
    }

    // Generate JWT token
    const token = jwt.sign(
      {
        id: user.id,
        email: user.email,
        role: "user"
      },
      process.env.JWT_SECRET,
      { expiresIn: process.env.JWT_EXPIRE || "7d" }
    );

    res.status(200).json({
      message: "Login successful",
      token,
      user: {
        id: user.id,
        email: user.email
      }
    });
  } catch (error) {
    res.status(500).json({ error: "Login failed" });
  }
};

exports.register = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Validation
    if (!email || !password) {
      return res.status(400).json({ error: "Email and password required" });
    }

    // Check if user exists
    if (users.find(u => u.email === email)) {
      return res.status(409).json({ error: "Email already registered" });
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);

    const newUser = {
      id: users.length + 1,
      email,
      password: hashedPassword
    };

    users.push(newUser);

    res.status(201).json({
      message: "Registration successful",
      user: {
        id: newUser.id,
        email: newUser.email
      }
    });
  } catch (error) {
    res.status(500).json({ error: "Registration failed" });
  }
};

3. Frontend Integration Using Fetch API

What is Fetch API?

The Fetch API is a modern browser API for making HTTP requests. It's the replacement for XMLHttpRequest and provides a simpler, promise-based approach.

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

How Frontend Communicates with Backend

Frontend (Browser)
       ↓
   Fetch Request
       ↓
Backend Server
       ↓
Processing
       ↓
Send Response
       ↓
Frontend receives JSON
       ↓
Display/Process Data

GET Request Example

// Simple GET request
fetch("http://localhost:3000/api/v1/users")
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    console.log("Users:", data);
    // Update DOM
    displayUsers(data.data);
  })
  .catch(error => console.error("Error fetching users:", error));

// With query parameters
const params = new URLSearchParams({
  page: 1,
  limit: 10
});

fetch(`http://localhost:3000/api/v1/users?${params}`)
  .then(res => res.json())
  .then(data => console.log(data));

POST Request Example

// Create new user
fetch("http://localhost:3000/api/v1/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`  // Include JWT token
  },
  body: JSON.stringify({
    name: "John Doe",
    email: "john@example.com"
  })
})
  .then(response => {
    if (response.status === 201) {
      console.log("User created successfully");
      return response.json();
    } else if (response.status === 400) {
      throw new Error("Invalid input");
    } else if (response.status === 401) {
      throw new Error("Unauthorized - please login");
    }
  })
  .then(data => {
    console.log("New user:", data.data);
    // Refresh user list
    loadUsers();
  })
  .catch(error => console.error("Error creating user:", error));

Handling Errors

async function fetchUserData(userId) {
  try {
    const response = await fetch(`http://localhost:3000/api/v1/users/${userId}`);

    if (!response.ok) {
      // Handle different error statuses
      switch (response.status) {
        case 404:
          throw new Error("User not found");
        case 401:
          throw new Error("Please login first");
        case 500:
          throw new Error("Server error - please try again");
        default:
          throw new Error(`Error: ${response.status}`);
      }
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Fetch error:", error.message);
    // Update UI with error message
    showErrorMessage(error.message);
    throw error;
  }
}

Loading States

let isLoading = false;

async function loadUsers() {
  if (isLoading) return; // Prevent duplicate requests

  isLoading = true;
  showLoadingSpinner(true);

  try {
    const response = await fetch("http://localhost:3000/api/v1/users");
    const data = await response.json();

    displayUsers(data.data);
  } catch (error) {
    showErrorMessage("Failed to load users");
  } finally {
    isLoading = false;
    showLoadingSpinner(false);
  }
}

Complete Frontend Integration Example

Create frontend/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>API Integration - User Management</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      padding: 20px;
    }

    .container {
      max-width: 900px;
      margin: 0 auto;
      background: white;
      border-radius: 10px;
      padding: 30px;
      box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
    }

    h1 {
      color: #333;
      margin-bottom: 30px;
      text-align: center;
    }

    .auth-section {
      background: #f5f5f5;
      padding: 20px;
      border-radius: 8px;
      margin-bottom: 30px;
    }

    .form-group {
      margin-bottom: 15px;
    }

    label {
      display: block;
      margin-bottom: 5px;
      color: #333;
      font-weight: 500;
    }

    input, textarea {
      width: 100%;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
      font-size: 14px;
    }

    button {
      background: #667eea;
      color: white;
      padding: 10px 20px;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      font-weight: 600;
      margin-right: 10px;
    }

    button:hover {
      background: #764ba2;
    }

    .users-section {
      margin-top: 30px;
    }

    .user-card {
      background: #f9f9f9;
      border: 1px solid #ddd;
      padding: 15px;
      margin: 10px 0;
      border-radius: 5px;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .user-info h3 {
      margin: 5px 0;
      color: #333;
    }

    .user-info p {
      color: #666;
      font-size: 14px;
    }

    .user-actions button {
      padding: 5px 10px;
      font-size: 13px;
      margin: 0 5px;
    }

    .loading {
      text-align: center;
      padding: 20px;
      color: #666;
    }

    .spinner {
      border: 4px solid #f3f3f3;
      border-top: 4px solid #667eea;
      border-radius: 50%;
      width: 20px;
      height: 20px;
      animation: spin 1s linear infinite;
      margin: 10px auto;
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    .error {
      background: #fee;
      color: #c33;
      padding: 15px;
      border-radius: 5px;
      margin: 10px 0;
    }

    .success {
      background: #efe;
      color: #3c3;
      padding: 15px;
      border-radius: 5px;
      margin: 10px 0;
    }

    .token-display {
      background: #f0f0f0;
      padding: 10px;
      border-radius: 5px;
      word-break: break-all;
      font-size: 12px;
      font-family: monospace;
      max-height: 100px;
      overflow-y: auto;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>📱 API Integration - User Management</h1>

    <!-- Authentication Section -->
    <div class="auth-section">
      <h2>Login</h2>
      <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" id="email" placeholder="user@example.com" value="user@example.com">
      </div>
      <div class="form-group">
        <label for="password">Password:</label>
        <input type="password" id="password" placeholder="password" value="password123">
      </div>
      <button onclick="login()">Login</button>

      <div id="tokenDisplay" style="margin-top: 15px; display: none;">
        <p><strong>JWT Token:</strong></p>
        <div class="token-display" id="tokenValue"></div>
        <button onclick="logout()" style="margin-top: 10px;">Logout</button>
      </div>
    </div>

    <!-- Message Display -->
    <div id="message"></div>

    <!-- Create User Section -->
    <div class="auth-section" style="margin-top: 30px;">
      <h2>Create New User</h2>
      <div class="form-group">
        <label for="newName">Name:</label>
        <input type="text" id="newName" placeholder="Enter name">
      </div>
      <div class="form-group">
        <label for="newEmail">Email:</label>
        <input type="email" id="newEmail" placeholder="Enter email">
      </div>
      <button onclick="createUser()">Create User</button>
    </div>

    <!-- Users List Section -->
    <div class="users-section">
      <h2>Users List</h2>
      <button onclick="loadUsers()">🔄 Refresh</button>
      <div id="usersList"></div>
    </div>
  </div>

  <script src="app.js"></script>
</body>
</html>

Create frontend/app.js:

const API_BASE_URL = "http://localhost:3000/api/v1";
let authToken = localStorage.getItem("authToken");

// ============ AUTHENTICATION ============

async function login() {
  const email = document.getElementById("email").value;
  const password = document.getElementById("password").value;

  if (!email || !password) {
    showMessage("Email and password required", "error");
    return;
  }

  try {
    const response = await fetch(`${API_BASE_URL}/auth/login`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, password })
    });

    const data = await response.json();

    if (response.ok) {
      authToken = data.token;
      localStorage.setItem("authToken", authToken);
      showMessage("Login successful!", "success");
      displayToken(authToken);
      loadUsers();
    } else {
      showMessage(data.error || "Login failed", "error");
    }
  } catch (error) {
    showMessage("Error: " + error.message, "error");
  }
}

function logout() {
  authToken = null;
  localStorage.removeItem("authToken");
  document.getElementById("tokenDisplay").style.display = "none";
  showMessage("Logged out successfully", "success");
  loadUsers();
}

function displayToken(token) {
  document.getElementById("tokenDisplay").style.display = "block";
  document.getElementById("tokenValue").textContent = token;
}

// ============ USER OPERATIONS ============

async function loadUsers() {
  const usersList = document.getElementById("usersList");
  usersList.innerHTML = '<div class="loading"><div class="spinner"></div> Loading users...</div>';

  try {
    const response = await fetch(`${API_BASE_URL}/users`);
    const data = await response.json();

    if (response.ok && data.data.length > 0) {
      usersList.innerHTML = data.data.map(user => `
        <div class="user-card">
          <div class="user-info">
            <h3>${user.name || 'N/A'}</h3>
            <p>📧 ${user.email}</p>
            <p>🕐 Created: ${new Date(user.createdAt).toLocaleDateString()}</p>
          </div>
          <div class="user-actions">
            <button onclick="deleteUser(${user.id})">Delete</button>
          </div>
        </div>
      `).join("");
    } else {
      usersList.innerHTML = "<p>No users found</p>";
    }
  } catch (error) {
    usersList.innerHTML = `<div class="error">Error loading users: ${error.message}</div>`;
  }
}

async function createUser() {
  const name = document.getElementById("newName").value;
  const email = document.getElementById("newEmail").value;

  if (!name || !email) {
    showMessage("Name and email required", "error");
    return;
  }

  if (!authToken) {
    showMessage("Please login first", "error");
    return;
  }

  try {
    const response = await fetch(`${API_BASE_URL}/users`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${authToken}`
      },
      body: JSON.stringify({ name, email })
    });

    const data = await response.json();

    if (response.ok) {
      showMessage("User created successfully!", "success");
      document.getElementById("newName").value = "";
      document.getElementById("newEmail").value = "";
      loadUsers();
    } else {
      showMessage(data.error || "Error creating user", "error");
    }
  } catch (error) {
    showMessage("Error: " + error.message, "error");
  }
}

async function deleteUser(userId) {
  if (!authToken) {
    showMessage("Please login first", "error");
    return;
  }

  if (!confirm("Are you sure?")) return;

  try {
    const response = await fetch(`${API_BASE_URL}/users/${userId}`, {
      method: "DELETE",
      headers: { "Authorization": `Bearer ${authToken}` }
    });

    if (response.ok) {
      showMessage("User deleted successfully!", "success");
      loadUsers();
    } else {
      showMessage("Error deleting user", "error");
    }
  } catch (error) {
    showMessage("Error: " + error.message, "error");
  }
}

// ============ UTILITIES ============

function showMessage(text, type) {
  const messageDiv = document.getElementById("message");
  messageDiv.className = type;
  messageDiv.textContent = text;

  setTimeout(() => {
    messageDiv.textContent = "";
  }, 4000);
}

// Load users on page load
window.addEventListener("load", () => {
  loadUsers();
  if (authToken) {
    displayToken(authToken);
  }
});

4. Authentication Flow

Complete Authentication System

Login Flow:

1. User enters email/password
   ↓
2. Frontend sends POST to /api/auth/login
   ↓
3. Backend verifies credentials
   ↓
4. Backend generates JWT token
   ↓
5. Token sent back to frontend
   ↓
6. Frontend stores token (localStorage)
   ↓
7. Token sent in Authorization header for protected routes
   ↓
8. Backend verifies token with middleware
   ↓
9. Route handler executes

Backend Login Endpoint

Already shown in section 2 as authController.js. Key points:

// 1. Verify credentials
const user = users.find(u => u.email === email);
const isPasswordValid = await bcrypt.compare(password, user.password);

// 2. Generate JWT token
const token = jwt.sign(
  { id: user.id, email: user.email },
  process.env.JWT_SECRET,
  { expiresIn: "7d" }
);

// 3. Return token
res.json({ token, user });

JWT Token Structure

A JWT consists of three parts separated by dots:

Header.Payload.Signature

Header (Base64 encoded):

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload (Base64 encoded):

{
  "id": 1,
  "email": "user@example.com",
  "role": "user",
  "iat": 1705335600,
  "exp": 1706194800
}

Signature (HMAC SHA256):

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

Frontend Token Storage

// After login, store token
localStorage.setItem("authToken", token);

// Retrieve token
const token = localStorage.getItem("authToken");

// Send with requests
fetch(url, {
  headers: {
    "Authorization": `Bearer ${token}`
  }
});

// Clear on logout
localStorage.removeItem("authToken");

Protected Routes Middleware

const auth = (req, res, next) => {
  try {
    // Extract token from header
    const token = req.headers.authorization?.split(" ")[1];

    if (!token) {
      return res.status(401).json({ error: "No token provided" });
    }

    // Verify token
    const decoded = jwt.verify(token, process.env.JWT_SECRET);

    // Attach user to request
    req.user = decoded;
    next();
  } catch (error) {
    res.status(401).json({ error: "Invalid token" });
  }
};

Frontend Token Management

class AuthManager {
  static setToken(token) {
    localStorage.setItem("authToken", token);
  }

  static getToken() {
    return localStorage.getItem("authToken");
  }

  static removeToken() {
    localStorage.removeItem("authToken");
  }

  static isAuthenticated() {
    return !!this.getToken();
  }

  static getHeaders() {
    const token = this.getToken();
    return {
      "Content-Type": "application/json",
      ...(token && { "Authorization": `Bearer ${token}` })
    };
  }
}

// Usage
async function makeAuthenticatedRequest(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: AuthManager.getHeaders()
  });

  if (response.status === 401) {
    AuthManager.removeToken();
    window.location.href = "/login";
  }

  return response;
}

5. Integrating Two Different Systems

Real-World Scenario

System A: Your backend server System B: External weather API service

Frontend (React/Vue/HTML)
        ↓
Backend Server (Node.js)
        ↓
External API (OpenWeatherMap)
        ↓
Get weather data
        ↓
Transform response
        ↓
Return to frontend

Backend Calling External API

Create controllers/weatherController.js:

const axios = require("axios");

const EXTERNAL_API_KEY = process.env.WEATHER_API_KEY;
const EXTERNAL_API_URL = "https://api.openweathermap.org/data/2.5/weather";

// Cache to reduce API calls
const weatherCache = new Map();
const CACHE_DURATION = 10 * 60 * 1000; // 10 minutes

exports.getWeather = async (req, res) => {
  try {
    const { city } = req.query;

    if (!city) {
      return res.status(400).json({ error: "City parameter required" });
    }

    // Check cache
    if (weatherCache.has(city)) {
      const cached = weatherCache.get(city);
      if (Date.now() - cached.timestamp < CACHE_DURATION) {
        console.log(`✓ Returning cached weather for ${city}`);
        return res.json({ data: cached.data, cached: true });
      }
    }

    // Call external API
    const response = await axios.get(EXTERNAL_API_URL, {
      params: {
        q: city,
        appid: EXTERNAL_API_KEY,
        units: "metric" // Celsius
      },
      timeout: 5000 // 5 second timeout
    });

    // Transform response
    const transformedData = {
      city: response.data.name,
      country: response.data.sys.country,
      temperature: response.data.main.temp,
      feelsLike: response.data.main.feels_like,
      humidity: response.data.main.humidity,
      pressure: response.data.main.pressure,
      description: response.data.weather[0].description,
      icon: response.data.weather[0].main,
      windSpeed: response.data.wind.speed,
      cloudiness: response.data.clouds.all
    };

    // Cache response
    weatherCache.set(city, {
      data: transformedData,
      timestamp: Date.now()
    });

    res.json({ data: transformedData, cached: false });
  } catch (error) {
    handleExternalApiError(error, res);
  }
};

function handleExternalApiError(error, res) {
  if (error.response) {
    // API returned error status
    if (error.response.status === 404) {
      res.status(404).json({ error: "City not found" });
    } else if (error.response.status === 401) {
      res.status(500).json({ error: "API authentication failed" });
    } else {
      res.status(error.response.status).json({ error: "External API error" });
    }
  } else if (error.code === "ECONNABORTED") {
    res.status(504).json({ error: "External API timeout" });
  } else {
    res.status(500).json({ error: "Failed to fetch weather data" });
  }
}

Response Transformation

// Raw API response
{
  "coord": {"lon": 10.99, "lat": 44.34},
  "weather": [{"id": 500, "main": "Rain", "description": "light rain"}],
  "main": {"temp": 10.94, "feels_like": 10.03, "humidity": 72},
  ...
}

// Transform to clean response
{
  "city": "Zocca",
  "temperature": 10.94,
  "description": "light rain",
  "humidity": 72,
  "windSpeed": 6.5
}

// Benefits:
// 1. Only return needed fields
// 2. Consistent naming
// 3. Easier for frontend
// 4. Hide API structure changes

Rate Limiting Considerations

const rateLimit = require("express-rate-limit");

// Rate limit external API calls
const externalApiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 50, // Max 50 requests per minute
  message: "Too many API requests",
  keyGenerator: (req) => req.user?.id || req.ip // Per user or IP
});

app.get("/api/weather", externalApiLimiter, weatherController.getWeather);

Caching Strategy

class CacheManager {
  constructor(duration = 5 * 60 * 1000) {
    this.cache = new Map();
    this.duration = duration;
  }

  set(key, value) {
    this.cache.set(key, {
      value,
      timestamp: Date.now()
    });
  }

  get(key) {
    const item = this.cache.get(key);

    if (!item) return null;

    // Check if expired
    if (Date.now() - item.timestamp > this.duration) {
      this.cache.delete(key);
      return null;
    }

    return item.value;
  }

  clear() {
    this.cache.clear();
  }
}

const apiCache = new CacheManager(10 * 60 * 1000); // 10 minutes

app.get("/api/weather/:city", (req, res) => {
  const { city } = req.params;

  // Try cache first
  const cached = apiCache.get(city);
  if (cached) {
    return res.json({ ...cached, cached: true });
  }

  // Fetch from external API
  fetchWeatherFromAPI(city)
    .then(data => {
      apiCache.set(city, data); // Cache for next time
      res.json({ ...data, cached: false });
    });
});

Error Handling Best Practices

async function callExternalAPI(url, options = {}) {
  const maxRetries = 3;
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await axios.get(url, {
        timeout: 5000,
        ...options
      });

      return response.data;
    } catch (error) {
      lastError = error;

      // Retry logic
      if (attempt < maxRetries && isRetryable(error)) {
        const delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  throw lastError;
}

function isRetryable(error) {
  // Retry on network errors or 5xx
  return !error.response || error.response.status >= 500;
}

6. Database Integration

MongoDB Example with Mongoose

Installation:

npm install mongoose

Create config/db.js:

const mongoose = require("mongoose");

const connectDB = async () => {
  try {
    const conn = await mongoose.connect(process.env.MONGODB_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });

    console.log(`✓ MongoDB Connected: ${conn.connection.host}`);
    return conn;
  } catch (error) {
    console.error(`Error: ${error.message}`);
    process.exit(1);
  }
};

module.exports = connectDB;

Create models/User.js:

const mongoose = require("mongoose");
const bcrypt = require("bcrypt");

const userSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: [true, "Please provide a name"],
      trim: true,
      minlength: [2, "Name must be at least 2 characters"]
    },
    email: {
      type: String,
      required: [true, "Please provide an email"],
      unique: true,
      lowercase: true,
      match: [
        /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/,
        "Please provide a valid email"
      ]
    },
    password: {
      type: String,
      required: [true, "Please provide a password"],
      minlength: [6, "Password must be at least 6 characters"],
      select: false // Don't return password by default
    },
    role: {
      type: String,
      enum: ["user", "admin"],
      default: "user"
    },
    isActive: {
      type: Boolean,
      default: true
    }
  },
  {
    timestamps: true // Adds createdAt and updatedAt
  }
);

// Hash password before saving
userSchema.pre("save", async function(next) {
  if (!this.isModified("password")) return next();

  try {
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
  } catch (error) {
    next(error);
  }
});

// Method to compare passwords
userSchema.methods.comparePassword = async function(enteredPassword) {
  return await bcrypt.compare(enteredPassword, this.password);
};

module.exports = mongoose.model("User", userSchema);

Updated Controller with Database

const User = require("../models/User");

// GET all users with pagination
exports.getAllUsers = async (req, res, next) => {
  try {
    const { page = 1, limit = 10 } = req.query;

    const skip = (page - 1) * limit;

    const users = await User.find()
      .skip(skip)
      .limit(parseInt(limit))
      .select("-password"); // Exclude password

    const total = await User.countDocuments();

    res.status(200).json({
      data: users,
      pagination: {
        total,
        page: parseInt(page),
        pages: Math.ceil(total / limit)
      }
    });
  } catch (error) {
    next(error);
  }
};

// GET single user
exports.getUserById = async (req, res, next) => {
  try {
    const { id } = req.params;

    // Validate MongoDB ObjectId
    if (!id.match(/^[0-9a-fA-F]{24}$/)) {
      return res.status(400).json({ error: "Invalid user ID" });
    }

    const user = await User.findById(id).select("-password");

    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }

    res.status(200).json({ data: user });
  } catch (error) {
    next(error);
  }
};

// CREATE user
exports.createUser = async (req, res, next) => {
  try {
    const { name, email, password } = req.body;

    // Validation
    if (!name || !email || !password) {
      return res.status(400).json({
        error: "Name, email, and password are required"
      });
    }

    // Check if email exists
    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(409).json({ error: "Email already exists" });
    }

    // Create user
    const user = new User({ name, email, password });
    await user.save();

    res.status(201).json({
      message: "User created successfully",
      data: {
        id: user._id,
        name: user.name,
        email: user.email
      }
    });
  } catch (error) {
    if (error.name === "ValidationError") {
      const messages = Object.values(error.errors).map(err => err.message);
      return res.status(400).json({ error: messages });
    }
    next(error);
  }
};

// UPDATE user
exports.updateUser = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { name, email } = req.body;

    if (!id.match(/^[0-9a-fA-F]{24}$/)) {
      return res.status(400).json({ error: "Invalid user ID" });
    }

    const user = await User.findByIdAndUpdate(
      id,
      { name, email },
      { new: true, runValidators: true }
    );

    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }

    res.status(200).json({
      message: "User updated successfully",
      data: user
    });
  } catch (error) {
    next(error);
  }
};

// DELETE user
exports.deleteUser = async (req, res, next) => {
  try {
    const { id } = req.params;

    if (!id.match(/^[0-9a-fA-F]{24}$/)) {
      return res.status(400).json({ error: "Invalid user ID" });
    }

    const user = await User.findByIdAndDelete(id);

    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }

    res.status(200).json({
      message: "User deleted successfully",
      data: user
    });
  } catch (error) {
    next(error);
  }
};

Database Connection in Server

Update server.js:

const express = require("express");
const dotenv = require("dotenv");
const connectDB = require("./config/db");

dotenv.config();

const app = express();

// Connect to database
connectDB();

app.use(express.json());

// Routes
app.use("/api/v1/users", require("./routes/users"));

app.listen(process.env.PORT || 3000, () => {
  console.log("Server running");
});

7. Advanced Concepts

API Versioning

// URL-based versioning (most common)
app.use("/api/v1/users", userRoutesV1);
app.use("/api/v2/users", userRoutesV2);

// Header-based versioning
app.get("/api/users", (req, res) => {
  const version = req.headers["api-version"] || "v1";

  if (version === "v2") {
    // Return v2 response
  } else {
    // Return v1 response
  }
});

// Query parameter versioning
app.get("/api/users?version=v2", (req, res) => {
  // Handle version
});

Pagination Implementation

exports.getAllUsers = async (req, res) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const skip = (page - 1) * limit;

    // Validate
    if (page < 1 || limit < 1) {
      return res.status(400).json({ error: "Invalid page or limit" });
    }

    const users = await User.find().skip(skip).limit(limit);
    const total = await User.countDocuments();

    res.json({
      data: users,
      pagination: {
        page,
        limit,
        total,
        pages: Math.ceil(total / limit),
        hasNext: page * limit < total,
        hasPrev: page > 1
      }
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
};

CORS Configuration

const cors = require("cors");

// Allow all origins (development only)
app.use(cors());

// Allow specific origins (production)
const whitelist = [
  "http://localhost:3000",
  "https://yourdomain.com",
  "https://app.yourdomain.com"
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || whitelist.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("CORS not allowed"));
    }
  },
  credentials: true, // Allow cookies
  methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
  allowedHeaders: ["Content-Type", "Authorization"]
}));

Logging System

Create utils/logger.js:

const fs = require("fs");
const path = require("path");

const logDir = path.join(__dirname, "../logs");

// Create logs directory if it doesn't exist
if (!fs.existsSync(logDir)) {
  fs.mkdirSync(logDir);
}

class Logger {
  formatMessage(level, message, data = {}) {
    return JSON.stringify({
      timestamp: new Date().toISOString(),
      level,
      message,
      ...data
    });
  }

  info(message, data) {
    const formatted = this.formatMessage("INFO", message, data);
    console.log(formatted);
    this.writeToFile("info.log", formatted);
  }

  error(message, error, data) {
    const formatted = this.formatMessage("ERROR", message, {
      ...data,
      error: error.message,
      stack: error.stack
    });
    console.error(formatted);
    this.writeToFile("error.log", formatted);
  }

  writeToFile(filename, message) {
    const filepath = path.join(logDir, filename);
    fs.appendFileSync(filepath, message + "\n");
  }
}

module.exports = new Logger();

API Documentation with Swagger

Create docs/swagger.yaml:

openapi: 3.0.0
info:
  title: API Integration Guide
  version: 1.0.0
  description: Complete REST API documentation

servers:
  - url: http://localhost:3000/api/v1
    description: Development server

paths:
  /users:
    get:
      summary: Get all users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
      responses:
        200:
          description: List of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
    post:
      summary: Create new user
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserInput'
      responses:
        201:
          description: User created
        401:
          description: Unauthorized

  /users/{id}:
    get:
      summary: Get user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        200:
          description: User data
        404:
          description: User not found

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
        createdAt:
          type: string
          format: date-time

    CreateUserInput:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Install and use Swagger UI:

npm install swagger-ui-express swagger-jsdoc
const swaggerUi = require("swagger-ui-express");
const YAML = require("yaml");
const fs = require("fs");

const swaggerDoc = YAML.parse(fs.readFileSync("./docs/swagger.yaml", "utf8"));

app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));

Rate Limiting

const rateLimit = require("express-rate-limit");

// Global rate limiter
const globalLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // 100 requests per window
  message: "Too many requests",
  standardHeaders: true,
  legacyHeaders: false
});

// Strict limiter for auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5, // Only 5 login attempts
  skipSuccessfulRequests: true // Don't count successful requests
});

app.use(globalLimiter);
app.post("/api/v1/auth/login", authLimiter, authController.login);

8. Architecture Explanation

Client-Server Architecture

┌─────────────────────────────────────────────────────────────┐
│                        CLIENT LAYER                         │
│  (Browser: HTML, CSS, JavaScript, React, Vue, Angular)     │
│  ┌─────────────────────────────────────────────────────┐  │
│  │  Makes HTTP requests to API endpoints               │  │
│  │  Displays data to user                              │  │
│  │  Handles user interactions                          │  │
│  └─────────────────────────────────────────────────────┘  │
└────────────────────────┬─────────────────────────────────────┘
                         │ HTTP/REST
                    Fetch API
                  XMLHttpRequest
          ┌────────────────────────┐
          │  Internet / Network    │
          └────────────────────────┘
                         │
┌────────────────────────┴─────────────────────────────────────┐
│                      SERVER LAYER                           │
│  (Node.js, Express, Python, Java, etc.)                    │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  Route Handler:                                      │  │
│  │  - Parse request                                     │  │
│  │  - Validate input                                    │  │
│  │  - Apply middleware                                  │  │
│  │  - Call business logic                               │  │
│  │  - Return response                                   │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  Business Logic Layer:                               │  │
│  │  - Controllers                                       │  │
│  │  - Services                                          │  │
│  │  - Validation                                        │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  Data Access Layer:                                  │  │
│  │  - Models                                            │  │
│  │  - Database queries                                  │  │
│  │  - Data transformation                               │  │
│  └──────────────────────────────────────────────────────┘  │
└────────────────────────┬─────────────────────────────────────┘
                         │
┌────────────────────────┴─────────────────────────────────────┐
│                    DATABASE LAYER                           │
│  (MongoDB, PostgreSQL, MySQL, etc.)                         │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  Stores and retrieves data                           │  │
│  │  Enforces schema/structure                           │  │
│  │  Performs transactions                               │  │
│  └──────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘

Request Lifecycle

1. CLIENT INITIATES REQUEST
   └─→ fetch("http://localhost:3000/api/v1/users", {
       method: "POST",
       headers: { "Authorization": "Bearer token" },
       body: { name: "John", email: "john@example.com" }
     })

2. HTTP REQUEST TRAVELS TO SERVER
   └─→ POST /api/v1/users HTTP/1.1
       Host: localhost:3000
       Authorization: Bearer token
       Content-Type: application/json
       Body: { name: "John", email: "john@example.com" }

3. SERVER RECEIVES REQUEST
   └─→ Express receives on port 3000

4. MIDDLEWARE PROCESSING
   └─→ app.use(express.json()) → Parse JSON body
   └─→ app.use(cors()) → Check CORS
   └─→ app.use(authMiddleware) → Verify JWT token

5. ROUTE MATCHING
   └─→ Router matches POST /api/v1/users
   └─→ Calls userController.createUser

6. CONTROLLER LOGIC
   └─→ Validate input data
   └─→ Check if email exists
   └─→ Prepare data

7. DATABASE OPERATION
   └─→ User.create({ name, email })
   └─→ Database stores data
   └─→ Returns created document

8. RESPONSE PREPARATION
   └─→ Format response
   └─→ Set HTTP status 201 (Created)
   └─→ Add headers

9. SERVER SENDS RESPONSE
   └─→ HTTP/1.1 201 Created
       Content-Type: application/json
       Body: { message: "...", data: {...} }

10. FRONTEND RECEIVES RESPONSE
    └─→ response.json() parses JSON
    └─→ .then() receives data
    └─→ Update DOM
    └─→ Display to user

Total Time: Usually 50-500ms depending on:
- Network latency
- Server processing time
- Database query time
- Response size

Data Flow Diagram

┌─────────────────────────────────────────────────────────────┐
│                      FRONTEND                              │
│                   User Interface                           │
│  Input: name, email → Create User Form                     │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ fetch POST request
                     ↓
┌─────────────────────────────────────────────────────────────┐
│                    BACKEND SERVER                          │
│                                                             │
│  1. Route Handler (/api/v1/users)                          │
│     └─→ Pass to controller                                 │
│                                                             │
│  2. Authentication Middleware                              │
│     └─→ Verify JWT token                                   │
│     └─→ Attach user to request                             │
│                                                             │
│  3. Controller (userController.createUser)                 │
│     └─→ Extract name, email from request                   │
│     └─→ Validate data                                      │
│     └─→ Check if email exists                              │
│                                                             │
│  4. Model/Service Layer                                    │
│     └─→ Prepare data object                                │
│     └─→ Call database method                               │
│                                                             │
│  5. Error Handling Middleware                              │
│     └─→ Catch any errors                                   │
│     └─→ Format error response                              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ Database query
                     ↓
┌─────────────────────────────────────────────────────────────┐
│                    DATABASE (MongoDB)                       │
│                                                             │
│  INSERT INTO users (name, email, createdAt)               │
│  VALUES ("John", "john@example.com", NOW())               │
│                                                             │
│  RETURNS: { _id: "...", name: "John", ... }               │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ Database result
                     ↓
┌─────────────────────────────────────────────────────────────┐
│                    BACKEND SERVER                          │
│                                                             │
│  6. Format Response                                        │
│     └─→ Status: 201 Created                                │
│     └─→ Body: { message: "...", data: {...} }             │
│     └─→ Headers: Content-Type: application/json            │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ HTTP response
                     ↓
┌─────────────────────────────────────────────────────────────┐
│                      FRONTEND                              │
│                                                             │
│  1. Receive Response                                       │
│     └─→ response.json()                                    │
│                                                             │
│  2. Update State                                           │
│     └─→ Add new user to users array                        │
│                                                             │
│  3. Update DOM                                             │
│     └─→ Display new user in table                          │
│     └─→ Show success message                               │
│     └─→ Clear form                                         │
│                                                             │
│  4. User Sees Result                                       │
│     └─→ New user appears on screen                         │
└─────────────────────────────────────────────────────────────┘

9. Best Practices

Security Practices

// 1. Input Validation
const validateEmail = (email) => {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
};

// 2. Sanitize Input
const sanitizeInput = (input) => {
  return input.trim().replace(/[<>]/g, "");
};

// 3. Secure Password Hashing
const bcrypt = require("bcrypt");
const hashedPassword = await bcrypt.hash(password, 10);

// 4. Use HTTPS (always in production)
// 5. Secure JWT Secret
const JWT_SECRET = process.env.JWT_SECRET; // Store in env

// 6. Rate Limiting
const rateLimit = require("express-rate-limit");
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));

// 7. CORS Whitelist
const whitelist = ["https://yourdomain.com"];
app.use(cors({ origin: whitelist }));

// 8. SQL Injection Prevention (if using SQL)
// Use parameterized queries
db.query("SELECT * FROM users WHERE id = ?", [userId]);

// 9. XSS Prevention
// Sanitize output in frontend
const sanitizeOutput = (text) => {
  const div = document.createElement("div");
  div.textContent = text;
  return div.innerHTML;
};

// 10. CSRF Protection (if using cookies)
const csrf = require("csurf");
app.use(csrf());

Folder Structure Scaling

For Small Projects (< 5 endpoints):
app/
├── server.js
├── routes.js
└── .env

For Medium Projects (5-20 endpoints):
app/
├── server.js
├── routes/
│   ├── users.js
│   └── posts.js
├── controllers/
│   ├── userController.js
│   └── postController.js
├── middleware/
│   └── auth.js
├── models/
│   ├── User.js
│   └── Post.js
└── .env

For Large Projects (20+ endpoints):
app/
├── server.js
├── config/
│   ├── db.js
│   └── env.js
├── api/
│   ├── v1/
│   │   ├── routes/
│   │   ├── controllers/
│   │   ├── services/
│   │   └── middleware/
│   └── v2/
│       ├── routes/
│       ├── controllers/
│       └── services/
├── models/
├── utils/
├── middleware/
├── tests/
└── .env

Clean Code Structure

// GOOD: Clear separation of concerns
// routes/users.js
const router = express.Router();
router.post("/", auth, validateUserInput, userController.createUser);

// controllers/userController.js
exports.createUser = async (req, res, next) => {
  try {
    const user = await userService.createUser(req.body);
    res.status(201).json({ data: user });
  } catch (error) {
    next(error);
  }
};

// services/userService.js
exports.createUser = async (userData) => {
  validateUserData(userData);
  return await User.create(userData);
};

// BAD: Everything in one place
app.post("/users", (req, res) => {
  const { name, email } = req.body;
  // validation, database, response all mixed
});

Separation of Concerns

// User Model - Handles data structure
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
}

// User Service - Handles business logic
class UserService {
  create(userData) {
    // Validate
    // Transform
    // Save to DB
  }
}

// User Controller - Handles HTTP requests
class UserController {
  async createUser(req, res) {
    // Extract from request
    // Call service
    // Send response
  }
}

// User Router - Handles routing
router.post("/users", userController.createUser);

Environment Based Configuration

// config/config.js
const config = {
  development: {
    port: 3000,
    database: "mongodb://localhost:27017/api_dev",
    jwtExpire: "7d",
    logLevel: "debug"
  },
  production: {
    port: process.env.PORT,
    database: process.env.DATABASE_URL,
    jwtExpire: "1d",
    logLevel: "error"
  },
  test: {
    port: 3001,
    database: "mongodb://localhost:27017/api_test",
    jwtExpire: "1h",
    logLevel: "warn"
  }
};

const env = process.env.NODE_ENV || "development";
module.exports = config[env];

10. Getting Started & Deployment

How to Run Locally

Prerequisites:

  • Node.js (v14+)
  • npm or yarn
  • MongoDB or PostgreSQL (for database examples)

Steps:

# 1. Clone repository
git clone https://github.com/yourusername/API-Integration.git
cd API-Integration

# 2. Install dependencies
npm install

# 3. Create .env file
cp .env.example .env

# 4. Update .env with your values
# PORT=3000
# MONGODB_URI=mongodb://localhost:27017/api_db
# JWT_SECRET=your_secret_key

# 5. Start MongoDB (if using)
mongod

# 6. Start server
npm start
# OR for development with auto-reload
npm run dev

# 7. Server running
# ✓ Server running on http://localhost:3000

Testing with Postman

  1. Create request in Postman:

    Method: POST
    URL: http://localhost:3000/api/v1/users
    Headers:
      - Content-Type: application/json
      - Authorization: Bearer {token}
    Body (JSON):
    {
      "name": "John Doe",
      "email": "john@example.com"
    }
    
  2. Test flow:

    • POST /api/v1/auth/login → Get token
    • Copy token from response
    • POST /api/v1/users with Authorization header
    • Should get 201 Created response

Frontend Setup

# 1. Open frontend/index.html in browser
# OR use local server
npx http-server frontend/

# 2. Update API_BASE_URL in frontend/app.js
const API_BASE_URL = "http://localhost:3000/api/v1";

# 3. Test on http://localhost:8080

Package.json Scripts

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "jest --coverage",
    "lint": "eslint .",
    "format": "prettier --write .",
    "deploy": "git push heroku main"
  }
}

Deployment Options

Heroku Deployment

# 1. Create Heroku app
heroku create your-app-name

# 2. Set environment variables
heroku config:set JWT_SECRET=your_secret
heroku config:set MONGODB_URI=your_mongodb_uri

# 3. Deploy
git push heroku main

# 4. View logs
heroku logs --tail

Docker Deployment

Create Dockerfile:

FROM node:16

WORKDIR /app

COPY package.json .
RUN npm install

COPY . .

ENV PORT=3000
EXPOSE 3000

CMD ["node", "server.js"]
# Build and run
docker build -t api-integration .
docker run -p 3000:3000 -e JWT_SECRET=secret api-integration

AWS EC2 Deployment

# 1. SSH into EC2 instance
ssh -i key.pem ubuntu@your-instance-ip

# 2. Install Node
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. Clone and setup
git clone your-repo
cd API-Integration
npm install

# 4. Install PM2 for process management
npm install -g pm2
pm2 start server.js
pm2 save
pm2 startup

Skills Demonstrated

This API Integration Guide demonstrates:

Backend Development

  • REST API design
  • Express.js framework
  • CRUD operations
  • Error handling
  • Authentication (JWT, bcrypt)
  • Database integration (MongoDB/PostgreSQL)
  • Middleware implementation

Frontend Development

  • Fetch API
  • Async/await
  • DOM manipulation
  • Form handling
  • Loading states
  • Error handling

Software Architecture

  • Client-server architecture
  • Separation of concerns
  • MVC pattern
  • Design patterns
  • Scalable folder structure

Security

  • Password hashing
  • JWT authentication
  • Input validation
  • CORS configuration
  • Rate limiting
  • HTTPS best practices

Database

  • Data modeling
  • Schema validation
  • Query optimization
  • Pagination
  • Indexing

DevOps & Deployment

  • Environment configuration
  • Docker containerization
  • Heroku deployment
  • CI/CD concepts
  • Logging and monitoring

Professional Development

  • Clean code principles
  • Error handling
  • API documentation (Swagger)
  • Testing (Postman)
  • Version control (Git)

Conclusion

This comprehensive guide covers everything needed to understand, build, and deploy professional REST APIs. By following this guide, you'll develop:

  1. Strong Foundation - Understanding of APIs, HTTP, and web architecture
  2. Practical Skills - Building real production-grade APIs
  3. Security Awareness - Best practices for securing applications
  4. Problem-Solving - Handling errors, authentication, and system integration
  5. Professional Standards - Clean code, documentation, deployment

Next Steps

  1. Practice - Build your own API using this guide
  2. Expand - Add more features (caching, websockets, queuing)
  3. Learn - Explore GraphQL, microservices, testing frameworks
  4. Deploy - Put your API live using Heroku, AWS, or DigitalOcean
  5. Contribute - Share your learning with the community

Resources

How Recruiters Can Review This Project

  1. Clone the repository

    git clone <your-repo-url>
    cd API-Integration
  2. Read the code

    • Start with server.js to understand structure
    • Review controllers for business logic
    • Check middleware for security implementation
    • Examine models for data structure
  3. Run the application

    • Follow "How to Run Locally" section
    • Test endpoints using provided frontend
    • Review console logs for debugging
  4. Assess your skills

    • Code organization and structure
    • Error handling implementation
    • Security practices
    • Documentation quality
    • Comments explaining complex logic

This project demonstrates:

  • ✅ Full stack capabilities
  • ✅ Professional code quality
  • ✅ Security awareness
  • ✅ Ability to build scalable systems
  • ✅ Communication through documentation
  • ✅ Best practices implementation

Last Updated: February 2024 Version: 1.0.0 License: MIT


Made with ❤️ for developers learning API integration

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors