QA
Senior LevelExpress JS

How do you architect an enterprise Express application using 3-layer Controller-Service-Repository patterns?

❓ Interview Prompt: Explain separation of concerns in Express: Routers/Controllers (HTTP layer), Service Layer (business logic), and Repository/DAO Layer (database access).

Putting database SQL queries and complex business logic directly inside Express route callbacks leads to unmaintainable spaghetti code. Enterprise applications enforce Separation of Concerns using a 3-Tier Layered Architecture:

1. Controller / Router Layer (The HTTP Interface):

Responsible ONLY for HTTP concerns: parsing 'req.body' / 'req.params', validating input syntax, calling the Service Layer, and sending 'res.status().json()'.

2. Service Layer (The Business Logic Engine):

Contains core domain rules, payment calculations, and workflow orchestrations.

Framework Agnostic: The service layer knows nothing about Express, 'req', or 'res'. It accepts plain JavaScript objects and returns Promises, making business logic 100% unit-testable!

3. Repository / Data Access Object (DAO) Layer:

Responsible ONLY for talking to databases (SQL, MongoDB, Redis) or external REST APIs.

Code Implementation Example

typescript
// 3. REPOSITORY LAYER (Database access only)
export class UserRepository {
  async findByEmail(email: string) {
    return await prisma.user.findUnique({ where: { email } });
  }
}

// 2. SERVICE LAYER (Business logic — Framework Agnostic!)
export class UserService {
  constructor(private userRepo: UserRepository) {}
  async registerUser(data: CreateUserDTO) {
    const existing = await this.userRepo.findByEmail(data.email);
    if (existing) throw new ConflictError('Email registered');
    return await this.userRepo.create(data);
  }
}

// 1. CONTROLLER LAYER (HTTP concerns only — parses req, formats res)
export class UserController {
  constructor(private userService: UserService) {}
  register = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const user = await this.userService.registerUser(req.body);
      res.status(201).json({ success: true, data: user });
    } catch (err) { next(err); }
  };
}
💡Enterprise 3-tier Controller-Service-Repository architecture in TypeScript.
🎯 Interview Key Takeaway

Isolate HTTP concerns in Controllers, domain logic in framework-agnostic Services, and database queries in Repositories.

#Architecture#MVC#Design Patterns#Senior
Back to all Express JS Questions→

More Express JS Interview Questions

Beginner LevelExpress JS

What is Express.js and how does the middleware pipeline work?

Beginner LevelExpress JS

What is the difference between req.params, req.query, and req.body?

Beginner LevelExpress JS

How does express.Router() work for building modular route controllers?