【问题标题】:CRUD operations using mongoose and express使用 mongoose 和 express 的 CRUD 操作
【发布时间】:2021-12-30 21:50:13
【问题描述】:

我正在使用 mongoose 创建一个快速应用程序,目的是将其连接到前端的 React。

我在下面为 客户控制器 列出了一些 CRUD 操作,但我不喜欢这种方法。

  1. 当使用 Customer.findById 和未找到的有效 ObjectID 时,它会返回带有 200 响应代码的 null。如果没有找到客户,我希望它返回 404。我意识到我可以将 catch 响应更改为 404,但我希望进行一些通用错误处理,以防服务器在请求期间出现故障或提供了无效的 ObjectId,这将我带到下一个项目。
  2. 如果我提供了无效的 ObjectId,我想提供一些有意义的消息,500 是正确的响应代码吗?
  3. 错误处理:我是否以正确的方式返回错误?当前错误返回带有错误消息的字符串。我应该返回 JSON 吗?例如res.status(500).json({error: error.message)。我计划连接它以做出反应(我仍在学习),并且我认为 UI 需要向用户显示这些消息?
  4. findByIdgetCustomerByIdupdateCustomerdeleteCustomer 中重复出现。我觉得这是不好的做法,必须有更精简的方法?
  5. 我想要一个函数来验证 ObjectId 是否有效。我知道我可以做到这一点是使用router.paramsroutes,但我不确定检查有效ID 是否应该在routes 文件中,因为看起来controller 应该处理?请参阅下面我做的另一个项目的路线示例。

根据上述情况,改进我的代码的最佳做法和建议方法是什么? 我已经阅读了来自 mongoose、mozilla 和 stackoverflow Q&A 的文档,但它们似乎没有解决这些问题(至少我找不到)。

我真的在接受一些指导或验证我所做的事情是正确还是错误。

customer.controller.js

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 示例 这是一个路由文件(与我当前的应用程序无关),作为我过去如何使用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;

【问题讨论】:

  • 你得到了一个ObjectId 的字符串值——使用本机NodeJS 驱动程序的ObjectId.isValid(id) 方法(或Mongoose 中的类似方法)检查​​该值是否有效。如果无效,则发送res.status(404).send({ message: "the provided id is not valid" })(在这种情况下,500 的响应状态代码不正确;它用于不可恢复的服务器端错误)。如果是有效的id,就可以使用它进行数据库操作;例如读取具有该 ID 的文档。如果您期望现有文档但未找到该文档,请发送相同的 404 响应。

标签: javascript node.js mongodb express mongoose


【解决方案1】:

我个人喜欢让错误处理更加全球化,所以我会写一些类似的东西

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' }
        })
}

那么就

 if (!artist) next({status:404 });

【讨论】:

  • 提示:express 中的错误处理程序应该是索引/服务器文件中最后加载的中间件。
【解决方案2】:

我也同意 Asaf Strilitz 的回答,但仍需要展示我在项目中所做的工作

创建自定义错误类

AppError.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;

创建错误处理中间件

errors.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;

创建一个中间件来验证对象ID

validateObjectId.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();
};

在你的 app.js 中

const { errors } = require("errors");


// At the end of all middlewares

// Error Handler Middleware
app.use(errors);

在您的路线文件中

const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const Artist = require("../models/Artist");
const loginRequired = require("../middleware/loginRequired");
const validateId = require("validateObjectId");

const {
  getArtists,
  addArtist,
  getArtistById,
  updateArtist,
  deleteArtist,
} = require("../controllers/artistController");

// Your routes
router
  .route("/:id")
  .get(validateId, loginRequired, getArtistById) // Get an artist by their id
  .put(validateId, loginRequired, updateArtist) // Update an artist by their id
  .delete(validateId, loginRequired, deleteArtist); // Delete an artist by their id


module.exports = router;

现在关于 findById 方法被重复,我没有看到任何不好的地方,因为它特定于数据库调用,您仍然可以在模型本身上引入静态方法或在 cntroller 上创建单个方法,但仍然需要检查它是否返回找到的对象与否并处理错误。

【讨论】:

    猜你喜欢
    • 2022-09-23
    • 2014-10-22
    • 2023-03-07
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    相关资源
    最近更新 更多