如何模块化Node.js+Express项目?拆分CRUD与路由逻辑
Got it, let's break down how to split your bloated app.js into clean controllers and routes—this will make your code way easier to maintain and scale. Here's a step-by-step guide tailored to your existing setup:
Step 1: Restructure Your Project
First, organize your files into a modular structure. This is the end goal:
your-project/ ├── app.js ├── models/ │ └── DNZmodels/ │ ├── FA.js │ └── FP.js ├── controllers/ │ ├── faController.js │ └── fpController.js └── routes/ ├── faRoutes.js ├── fpRoutes.js └── index.js
- controllers/: Holds all your CRUD business logic (database interactions, request/response handling)
- routes/: Defines API endpoints and maps them to controller functions
- models/: Keeps your Mongoose models as-is
Step 2: Move CRUD Logic to Controllers
Create controllers/faController.js and extract all your FA-related CRUD code from app.js into reusable functions:
const FA = require('../models/DNZmodels/FA'); // Create a new FA entry exports.createFA = (req, res) => { console.log("Erzeugen der Instanz FA.."); const fa = new FA(req.body); fa.save((err) => { if (err) { console.log(err); return res.status(400).send(err); } console.log("Instanz FA in Datenbank erzeugt!"); res.status(200).json({ message: 'FA-Instance created in database!' }); }); }; // Get all FA entries exports.getAllFAs = (req, res) => { FA.find((err, fas) => { if (err) return res.send(err); res.json(fas); }); }; // Get a single FA by ID (fixed your typo: was using `bear_id` instead of `FA_id`) exports.getFAById = (req, res) => { FA.findById(req.params.FA_id, (err, fa) => { if (err) return res.send(err); res.json(fa); }); }; // Update an existing FA exports.updateFA = (req, res) => { FA.findById(req.params.FA_id, (err, fa) => { if (err) return res.send(err); // Update fields with request body data (you can specify exact fields if needed) Object.assign(fa, req.body); fa.save((err) => { if (err) return res.send(err); res.json({ message: 'FA updated!' }); }); }); };
Repeat this pattern for fpController.js with your FP model logic.
Step 3: Define Routes in Separate Files
Create routes/faRoutes.js to map HTTP endpoints to your controller functions:
const express = require('express'); const router = express.Router(); const faController = require('../controllers/faController'); // Routes for /FA router.post('/', faController.createFA); router.get('/', faController.getAllFAs); // Routes for /FA/:FA_id router.get('/:FA_id', faController.getFAById); router.put('/:FA_id', faController.updateFA); module.exports = router;
Do the same for routes/fpRoutes.js with your FP routes.
Then create routes/index.js to bundle all your sub-routes (keeps app.js clean):
const express = require('express'); const router = express.Router(); const faRoutes = require('./faRoutes'); const fpRoutes = require('./fpRoutes'); // Mount sub-routes under their respective paths router.use('/FA', faRoutes); router.use('/FP', fpRoutes); module.exports = router;
Step 4: Clean Up app.js
Strip out all the old route logic and replace it with your modular routes. Your new app.js will only handle setup and middleware:
const express = require('express'); const app = express(); const bodyParser = require("body-parser"); const morgan = require("morgan"); const cors = require('cors'); const mongoose = require('mongoose'); const apiRoutes = require('./routes'); // Configure middleware app.use(morgan('dev')); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(cors()); // Database connection mongoose.connect('mongodb://localhost/DNZ'); const db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', () => console.log("DB connection alive")); // Main API router with global middleware const mainRouter = express.Router(); // Global middleware for all requests mainRouter.use((req, res, next) => { console.log('Something is happening.'); console.log('Today is:', new Date()); next(); }); // Test route mainRouter.get('/', (req, res) => { res.json({ message: 'Welcome to DNZ API!' }); }); // Mount all API routes under /DNZ mainRouter.use('/DNZ', apiRoutes); // Attach main router to the app app.use('/', mainRouter); // Start server const port = process.env.PORT || 5000; app.listen(port, () => console.log(`API running on port ${port}`));
Key Notes
- Separation of Concerns: Controllers handle "how" to process requests, routes handle "what" endpoints exist.
- Path Accuracy: Double-check relative paths when importing files (e.g.,
../models/DNZmodels/FAfrom the controllers folder). - Async/Await Upgrade: For cleaner code, replace callbacks with async/await in your controllers. Example:
exports.createFA = async (req, res) => { try { console.log("Erzeugen der Instanz FA.."); const fa = new FA(req.body); await fa.save(); console.log("Instanz FA in Datenbank erzeugt!"); res.status(200).json({ message: 'FA-Instance created in database!' }); } catch (err) { console.log(err); res.status(400).send(err); } };
内容的提问来源于stack exchange,提问作者MarcL

