Building an API with Express.js and Connecting It to the Frontend

When building modern web applications, APIs serve as the bridge between the backend (server-side logic) and the frontend (user interface). In this blog post, we’ll break down how an Express.js-based API works, its key components, and how it connects to a frontend application.

1. What is a Router in Express.js?

A router in Express.js is a way to organize API endpoints into modular and reusable components. Think of it as a "sub-application" that groups related routes together.

  • Why Use Routers?
    • Keeps code clean and modular.
    • Allows you to separate concerns (e.g., authentication routes in auth.js, product routes in products.js).

Example:

const express = require('express');
const router = express.Router();

// Define routes
router.post('/register', (req, res) => {
  res.send('Register endpoint');
});
router.post('/login', (req, res) => {
  res.send('Login endpoint');
});

// Export the router
module.exports = router;

This router can then be mounted in the main app:

const authRouter = require('./routes/auth');
app.use('/api/auth', authRouter);

2. Backend API Workflow

Here’s how a typical authentication API works:

a. POST /api/auth/register

  • Purpose: Registers a new user.
  • Steps:
    1. Check if the email already exists in the database.
    2. Hash the password using bcrypt.
    3. Save the user to the database.
    4. Return a JWT token for future authenticated requests.

b. POST /api/auth/login

  • Purpose: Logs in an existing user.
  • Steps:
    1. Verify if the email exists.
    2. Compare the provided password with the hashed password stored in the database.
    3. If valid, return a JWT token.

c. GET /api/auth/user

  • Purpose: Fetches data of the logged-in user.
  • Steps:
    1. Validate the JWT token using middleware.
    2. Return user data, excluding sensitive information like passwords.

Code Example for /register:

const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('./models/User'); // Mongoose model

router.post('/register', async (req, res) => {
  const { email, password } = req.body;

  // Check if user exists
  const existingUser = await User.findOne({ email });
  if (existingUser) return res.status(400).send('User already exists');

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

  // Save user to database
  const newUser = new User({ email, password: hashedPassword });
  await newUser.save();

  // Generate JWT token
  const token = jwt.sign({ id: newUser._id }, 'secretKey', { expiresIn: '1h' });

  res.status(201).json({ token });
});

3. Connecting the Backend to the Frontend

The frontend communicates with this API through HTTP requests.

Step 1: Registration/Login

The frontend sends a POST request to /api/auth/register or /api/auth/login with user credentials.

Example Frontend Code:

// Register a user
const response = await fetch('/api/auth/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: '[email protected]', password: '123456' }),
});

const data = await response.json();
console.log(data.token); // JWT token

Step 2: Storing JWT Token

After receiving the JWT token, store it securely (e.g., in localStorage or cookies):

localStorage.setItem('token', data.token);

Step 3: Making Authenticated Requests

For protected routes like /api/auth/user, include the JWT token in the request headers:

const token = localStorage.getItem('token');

const response = await fetch('/api/auth/user', {
  headers: { Authorization: `Bearer ${token}` },
});

const userData = await response.json();
console.log(userData);

4. Key Components of an Express API

Component Role
Express Router Organizes routes into modules for cleaner code.
Bcrypt Hashes passwords securely before storing them in a database.
JWT (JSON Web Token) Generates tokens for authenticating users across sessions.
Mongoose Models Defines schemas for MongoDB collections (e.g., users).
Auth Middleware Validates JWT tokens for protected routes like /api/auth/user.

Summary: Frontend vs Backend Roles

Frontend Backend
Sends HTTP requests to API endpoints. Handles requests and sends responses with data/logic.
Stores and uses tokens for auth. Generates and validates tokens using JWTs.
Displays user data (e.g., profile). Fetches and secures data from databases like MongoDB.

Why This Matters

  1. Security: Passwords are hashed, and JWT ensures only authenticated users access protected routes.
  2. Scalability: Modular routing and middleware make it easier to grow your application.
  3. Separation of Concerns: The frontend focuses on UI/UX while the backend handles logic and data.

This approach forms the backbone of most modern web apps, enabling seamless communication between frontend interfaces and backend systems.


Tags:

#NodeJS #ExpressJS #API #Authentication #WebDevelopment #FrontendBackendIntegration

Citations:
[1] https://rapidapi.com/blog/nodejs-express-rest-api-example/
[2] https://www.freecodecamp.org/news/the-express-handbook/
[3] https://dev.to/mrrishimeena/understanding-expressjs-router-nodejs-a-comprehensive-guide-59o8
[4] https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction
[5] https://dev.to/reiallenramos/create-an-express-api-static-and-dynamic-routes-33lb
[6] https://www.codecademy.com/article/what-is-express-js
[7] https://www.youtube.com/watch?v=1XxQBXl4Lv8
[8] https://www.freecodecamp.org/news/rest-api-design-best-practices-build-a-rest-api/
[9] https://www.topcoder.com/thrive/articles/routing-in-express-js
[10] https://kinsta.com/knowledgebase/what-is-express-js/