Skip to Main Content
Guides10 min readUpdated 24 March 2026

How to Scaffold Express.js & MongoDB REST APIs Using AI Prompt Architect

Express.js is the most popular Node.js framework, but its unopinionated nature means AI assistants generate wildly different patterns in every conversation. One session gives you callback-style error handling, the next uses async/await, and the third mixes both. A Master Prompt locks in your architectural decisions once and enforces them forever.

The Express Consistency Problem

Without a Master Prompt, AI-generated Express code has no memory of your decisions:

// ❌ Session 1: Callbacks
app.get('/users', (req, res) => {
  User.find({}, (err, users) => {
    if (err) return res.status(500).json({ error: err.message });
    res.json(users);
  });
});

// ❌ Session 2: Async/await, different error pattern
app.get('/users', async (req, res) => {
  try {
    const users = await User.find();
    res.json({ data: users, count: users.length });
  } catch (e) {
    res.status(500).send('Server error');
  }
});
Key insight: Express gives you freedom, but freedom without consistency produces unmaintainable APIs. A Master Prompt ensures every route follows the same patterns.

Step 1: Define Your Express Architecture

framework: Express.js 4.x
language: TypeScript (strict mode)
database: MongoDB with Mongoose ODM

project_structure:
  src/
    routes/       # Route definitions (thin — delegate to controllers)
    controllers/  # Business logic
    models/       # Mongoose schemas + models
    middleware/   # Auth, validation, error handling
    services/     # External integrations
    utils/        # Shared helpers
    config/       # Environment config
    types/        # TypeScript interfaces

conventions:
  - Async/await everywhere — no callbacks
  - Centralised error handler middleware
  - Joi/Zod validation on every route
  - Consistent JSON response shape: { data, meta, error }
  - HTTP status codes follow REST standards strictly

Step 2: Generated Patterns

The Master Prompt produces consistent controllers:

// controllers/users.controller.ts — Generated pattern
import { Request, Response, NextFunction } from 'express';
import { User } from '../models/user.model';
import { AppError } from '../utils/appError';
import { createUserSchema } from '../validators/user.validator';

export const getUsers = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { page = 1, limit = 20 } = req.query;
    const users = await User.find()
      .select('-password')
      .skip((+page - 1) * +limit)
      .limit(+limit)
      .lean();

    const total = await User.countDocuments();

    res.json({
      data: users,
      meta: { page: +page, limit: +limit, total, pages: Math.ceil(total / +limit) }
    });
  } catch (error) {
    next(error);
  }
};

export const createUser = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const validated = createUserSchema.parse(req.body);
    const user = await User.create(validated);
    res.status(201).json({ data: user });
  } catch (error) {
    next(error);
  }
};

Step 3: Error Handling Middleware

// middleware/errorHandler.ts
export const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {
  const status = err.statusCode || 500;
  const message = err.isOperational ? err.message : 'Internal server error';

  res.status(status).json({
    error: { message, code: err.code || 'INTERNAL_ERROR' },
    data: null
  });
};

Key Takeaways

  1. Thin routes, fat controllers — routes only define method + path + middleware chain
  2. Centralised error handling — every controller calls next(error), never sends errors directly
  3. Consistent response shape — every endpoint returns { data, meta, error }
  4. Validation first — Zod/Joi schema validation before any business logic executes
  5. TypeScript strict mode — catches type mismatches at compile time
Scaffold your API: Create a free account and generate a production-ready Express.js API in under 5 minutes.

This backend is ideal for powering a Next.js frontend. Learn how to lock your AI into App Router best practices with our Ultimate Next.js & React Master Prompt guide.

Ready to build better prompts?

Start using AI Prompt Architect for free today.

Get Started Free

Pydantic/Zod output schemas restrict responses to pre-defined fields, achieving 100% adherence to allowed data shapes an.Pydantic, 'Data Validation Using Python Type Hints…