Итак, вы на правильном пути.Есть много разных способов сделать это в зависимости от предпочтений, но один шаблон, который я видел довольно часто, - это использование обратного вызова в качестве способа интеграции.Например, предположим, у вас есть файл вашей модели:
exports.getPostById = (id, cb) => {
db.query('SELECT * FROM `posts` WHERE id=?', [id], function (err, result) {
if (err){
return cb(err); // or, alternatively, wrap this error in a custom error
}
// here, your logic is just returning whatever was returned
return cb(null, result);
});
};
Примечание. Я также разрешаю БД обрабатывать поиск идентификатора, так как это, вероятно, более эффективно для больших наборов данных.Вы не сказали, какой модуль БД вы используете, но у всех хороших есть какой-то способ выполнения параметризованных запросов, поэтому используйте все, что работает с вашим драйвером БД.
В любом случае, файл Model обрабатывает толькопри взаимодействии с данными контроллер затем обрабатывает веб-взаимодействие:
// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = (req, res, next, id) => {
model.getPostById(id, (err, post) => {
if (err) return next(err); // centralized error handler
req.post = post;
next();
});
}
export.getOnePost = (req, res, next) => {
if (req.post) {
return res.render('pages/post-page', req.post);
}
// again, central error handling
return next({ status: 404, message: 'Post not found' });
}
Я упомянул центральную обработку ошибок;Я предпочитаю это рассеянию логики обработки ошибок повсюду.Поэтому я либо делаю собственные ошибки для представления чего-либо, либо просто делаю то же самое, что и выше, где прикрепляю статус и сообщение к анонимному объекту.Либо будет работать для наших целей.Затем в файле промежуточного программного обеспечения вы можете иметь один или несколько обработчиков, самый простой из них:
// middleware/errors.js
module.exports = (err, req, res, next) => {
console.error(err); // log it
if (err.status) {
return res.status(err.status).render(`errors/${err.status}`, err.message);
}
return res.status(500).render('errors/500', err.message);
}
Наконец, в настройках маршрутизации вы можете сделать что-то вроде этого:
const postController = require('../controllers/postController');
const errorHandler = require('../middleware/errors.js');
const postRouter = express.Router();
postRouter.param('postId', postController.populatePost);
postRouter.get('/:postId', postController.getOnePost);
// other methods and routes
app.use('/posts', postRouter)
// later
app.use(errorHandler);
Как отмечалось в комментариях, некоторые люди предпочитают использовать синтаксис Promise для обратных вызовов.Я лично не нахожу их , которые намного чище, если только вы не используете синтаксис async / await.Например, если ваша библиотека db поддерживает обещания, вы можете изменить код модели, чтобы он выглядел так:
exports.getPostById = async (id, cb) => {
// again, this assumes db.query returns a Promise
return await db.query('SELECT * FROM `posts` WHERE id=?', [id]);
}
Тогда ваш код контроллера также должен измениться, чтобы справиться с этим:
// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = async (req, res, next, id) => {
try {
const post = await model.getPostById(id)
req.post = post
return next()
} catch (err) {
return next(err)
}
}