Facebook Pixel

Understanding the DevTinder Codebase Structure Models, Routes, and Middleware

Deep dive into the DevTinder backend codebase structure how models, routes, middlewares, and utils are organized and how they work together in a production Node.js app.

Understanding the DevTinder Codebase Structure

The DevTinder backend follows a modular structure that separates concerns: models handle data, routes handle HTTP, middlewares handle cross-cutting concerns, and utils provide helpers. Understanding this structure is key to navigating and extending the codebase.

The Entry Point: server.js

// src/server.js const http = require("http"); const app = require("./app"); const server = http.createServer(app); const { connectDatabase } = require("./config/database"); connectDatabase(); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); // Socket.io setup const io = require("./config/socket").init(server); require("./config/socketEvents")(io);

The server.js file creates an HTTP server from the Express app, connects to MongoDB, starts listening, and sets up Socket.io.

The Express App: app.js

// src/app.js const express = require("express"); const cookieParser = require("cookie-parser"); const cors = require("cors"); const morgan = require("morgan"); const app = express(); app.use(cors({ origin: process.env.CLIENT_URL, credentials: true })); app.use(express.json()); app.use(cookieParser()); app.use(morgan("dev")); // Routes app.use("/api", require("./routes/auth")); app.use("/api", require("./routes/profile")); app.use("/api", require("./routes/connection")); app.use("/api", require("./routes/feed")); app.use("/api", require("./routes/chat")); // 404 handler app.use((req, res) => { res.status(404).json({ message: "Route not found" }); }); // Global error handler app.use((err, req, res, next) => { const status = err.statusCode || 500; res.status(status).json({ message: err.message }); }); module.exports = app;

Models (src/models/)

Models define the data schema and interact with MongoDB:

  • user.js User schema (firstName, lastName, email, password, photoUrl, age, gender, about, skills)
  • connectionRequest.js ConnectionRequest schema (fromUserId, toUserId, status)
  • message.js Message schema (senderId, receiverId, text, timestamps)

Each model exports a Mongoose model. Models include:

  • Schema validation (required, min, max, enum)
  • Indexes (compound unique index on ConnectionRequest)
  • Instance methods (comparePassword on User)
  • Pre-save hooks (hash password before save)

Routes (src/routes/)

Routes handle HTTP requests and call the appropriate model methods:

  • auth.js POST /signup, POST /login, POST /logout
  • profile.js GET /profile/view, PATCH /profile/edit, POST /profile/photo
  • connection.js POST /request/send/:status/:toUserId, POST /request/review/:status/:requestId, GET /connections, GET /requests/received
  • feed.js GET /feed with pagination
  • chat.js GET /chat/:targetUserId (message history)

Each route file exports an Express Router that is mounted in app.js.

Middlewares (src/middlewares/)

Middlewares handle cross-cutting concerns:

  • auth.js Verifies JWT, attaches user to req.user
  • error.js Custom error class (AppError), async handler wrapper
  • validation.js Request body validation for specific routes

Utils (src/utils/)

Utility functions:

  • tokenAuth.js JWT generation and verification helpers
  • validators.js Email, password, and ObjectId validation functions
  • constants.js Status enums, error messages, configuration values

Config (src/config/)

Configuration files:

  • database.js MongoDB connection logic
  • socket.js Socket.io server initialization
  • socketEvents.js Socket.io event handlers (join, message, typing)

How It All Works Together

  1. A request comes in to POST /api/request/send/interested/64abc123
  2. Express matches the route in routes/connection.js
  3. The userAuth middleware verifies the JWT cookie and attaches req.user
  4. The route handler validates input, checks for duplicates, creates a ConnectionRequest
  5. The response is sent back as JSON
  6. If an error is thrown, the global error handler in app.js catches it

The Takeaway

The DevTinder codebase follows a clean modular structure: server.js (entry point), app.js (Express setup), models (data), routes (HTTP), middlewares (cross-cutting), utils (helpers), and config (database, socket). This separation makes the code easy to navigate, test, and extend.

server.js is the entry point. It creates an HTTP server from the Express app, connects to MongoDB, starts listening on the configured port, and sets up Socket.io for real-time chat.

Routes are split into separate files by feature: auth.js (signup, login, logout), profile.js (view, edit, photo), connection.js (send, review, list), feed.js (paginated feed), and chat.js (message history). Each exports an Express Router mounted in app.js.

Models define Mongoose schemas with field types, validation (required, min, max, enum), indexes (compound unique on ConnectionRequest), instance methods (comparePassword on User), and pre-save hooks (password hashing).

auth.js (JWT verification, attaches user to req.user), error.js (custom AppError class and async handler wrapper), and validation.js (request body validation for specific routes like connection requests).

Request hits Express, matches a route in routes/, passes through auth middleware (JWT verification), the route handler validates input and calls model methods, the response is sent as JSON, and any errors are caught by the global error handler in app.js.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.