我正在使用 mongoose 创建一个 Express 应用程序,目的是将其连接到前端的 React。
我在下面列出了一些客户控制器的 CRUD 操作,但这种方法有一些我不喜欢的地方。
Customer.findById
与未找到的有效 ObjectID 一起使用时,它会返回 null
以及 200 响应代码。 如果没有找到客户,我希望返回 404。 我意识到我可以将 catch
响应更改为 404,但我希望进行一些通用错误处理,以防服务器在请求期间出现故障或提供了无效的 ObjectId,这将我带到下一个项目。res.status(500).json({error: error.message)
。 我计划连接它来做出反应(我仍在学习),并且我认为 UI 需要向用户显示这些消息?findById
在 getCustomerById
、updateCustomer
和 deleteCustomer
中重复。 我觉得这是不好的做法,必须有更简化的方法吗?routes
来做到这一点,但我不确定检查有效 id 是否应该在 router.params
文件中,因为它看起来像是 routes
应该处理的事情?请参阅下面我所做的另一个项目的路线示例。
我确实在寻求一些指导或验证,以确定我所做的事情是正确还是错误。
customer.controller.js
controller
这是一个路线文件(与我当前的应用程序无关),并作为我过去如何使用 const Customer = require("../models/customer.model");
exports.getCustomers = async (req, res) => {
try {
const customers = await Customer.find();
res.status(200).json(customers);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.getCustomerById = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.addCustomer = async (req, res) => {
try {
const customer = new Customer(req.body);
await customer.save().then(res.status(201).json(customer));
} catch (error) {
res.status(500).send(error.message);
}
};
exports.updateCustomer = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
Object.assign(customer, req.body);
customer.save();
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.deleteCustomer = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
await customer.remove();
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
的示例提供。
router.params
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const Artist = require("../models/Artist");
const loginRequired = require("../middleware/loginRequired");
const {
getArtists,
addArtist,
getArtistById,
updateArtist,
deleteArtist,
} = require("../controllers/artistController");
router
.route("/")
.get(loginRequired, getArtists) // Get all artists
.post(loginRequired, addArtist); // Create a new artist
router
.route("/:id")
.get(loginRequired, getArtistById) // Get an artist by their id
.put(loginRequired, updateArtist) // Update an artist by their id
.delete(loginRequired, deleteArtist); // Delete an artist by their id
router.param("id", async (req, res, next, id) => {
// Check if the id is a valid Object Id
if (mongoose.isValidObjectId(id)) {
// Check to see if artist with valid id exists
const artist = await Artist.findOne({ _id: id });
if (!artist) res.status(400).json({ errors: "Artist not found" });
res.locals.artist = artist;
res.locals.artistId = id;
next();
} else {
res.status(400).json({ errors: "not a valid object Id" });
}
});
module.exports = router;
作为处理者
在您的索引/服务器文件中
constPrettyError = require('pretty-error')
const pe = new PrettyError()
const errorHandler = (err, req, res, next) => {
if (process.env.NODE_ENV !== 'test') {
console.log(pe.render(err))
}
return res
.status(err.status || 500)
.json({ error: { message: err.message || 'oops something went wrong' } })
}
module.exports = errorHandler
然后在你的处理程序中
app.use(errorHandler)
举个例子
} catch (err) {
next(err);
}
另请注意,如果您愿意,您也可以自定义此错误处理程序以根据状态切换大小写(或对象)自定义错误
if (!artist) next({ message: "Artist not found" ,status:404 });
然后就
const errorHandler = (err, req, res, next) => {
if (process.env.NODE_ENV !== 'test') {
console.log(pe.render(err))
}
const messagePerStatus = {
404: 'not found',
401: 'no authorization'
}
const message = messagePerStatus[err.status]
return res
.status(err.status || 500)
.json({
error: { message: message || err.message || 'oops something went wrong' }
})
}
创建自定义错误类
AppError.js
if (!artist) next({status:404 });
创建错误处理中间件
错误.js
class AppError extends Error {
constructor(statusCode, message) {
super();
// super(message);
this.statusCode = statusCode || 500 ;
this.message = message || "Error Something went wrong";
}
}
module.exports = AppError;
创建一个中间件来验证对象ID
validateObjectId.js
const AppError = require("../helpers/appError");
const errors = (err, req, res, next) => {
// console.log(err);
let error = { ...err };
error.statusCode = error.statusCode;
error.message = error.message;
res.status(error.statusCode).json({
statusCode: err.statusCode,
message: err.message,
});
};
exports.errors = errors;
在你的app.js中
const mongoose = require("mongoose");
const AppError = require("appError");
module.exports = function (req, res, next) {
const { _id } = req.params;
if (_id && !mongoose.Types.ObjectId.isValid(_id)) {
throw new AppError(422, "Invalid ID field in params");
}
next();
};
在你的路线文件中
const { errors } = require("errors");
// At the end of all middlewares
// Error Handler Middleware
app.use(errors);
现在关于重复 findById 方法,我没有看到任何不好的地方,因为它特定于数据库调用,您仍然可以在模型本身上引入静态方法或在 cntroller 上创建单个方法,但仍然需要检查它是否返回找到的对象或不,并处理该错误。