【问题标题】:best practice to validate POST request body验证 POST 请求正文的最佳实践
【发布时间】:2022-01-08 23:49:43
【问题描述】:

我的 Express API 公开了一个 POST 端点来创建用户,我需要在将数据插入数据库之前对其进行验证,我有两种方法:

方法 1:在控制器中包含模型的验证,并对每个模型重复:

// controllers/users.js

exports.createUser = async function (req, res) {
    const { username, email, password } = req.body;

    /* validation logic */

    /* interact with db */

方法二:将验证逻辑移至专用中间件:

// middleware/validators.js

exports.validateArticle = function (req, res, next) {};

exports.validateComment = function (req, res, next) {};

exports.validateUser = function (req, res, next) {
    const { username, email, password } = req.body;

    /* validation logic */

    if (!isValid) {
        return res.statusCode(400);
    }

    next();
};
// routes/users.js

const { validateUser } = require('../middlewares/validators');

router.route('/').post(validateUser, createUser);

我对方法 2 的担忧是,一种端点方法的逻辑会分散在许多文件中,但是这些方法中的哪一种遵循最佳实践?

【问题讨论】:

  • 我个人喜欢为每个关注点分开文件,我认为你声明快速路由器的地方看起来很干净

标签: javascript node.js express middleware


【解决方案1】:

我可以建议你使用现成的中间件express-validator,并像这样设置:

// src/validation/validation.js
const { validationResult } = require('express-validator');

const validate = (schemas) => {
    return async (req, res, next) => {
        await Promise.all(schemas.map((schema) => schema.run(req)));

        const result = validationResult(req);
        if (result.isEmpty()) {
            return next();
        }

        const errors = result.array();
        return res.send({
            message: 'Validation error',
            errors: errors,
        })
    };
}

module.exports = {
    validate
}

这是一个您可以像路由器中的中间件一样调用的函数,然后是一个包含验证规则的文件。

// src/validation/validationSchemas.js
const { body } = require('express-validator');

const addUserSchema = [
    body('username').isLength({ min: 4, max: 16 }).withMessage('Username must be at least 4 and no more than 16 characters'),
    body('email').isEmail().withMessage('Incorrect email')
];

module.exports = { addUserSchema }

在您的路由器中:

const { validate } = require('../validation/validation'); 
const { registrationSchema, loginSchema } = require('../validation/validationSchemas');

router.post('/registration', validate(registrationSchema), userController.registration);

【讨论】:

    【解决方案2】:

    问题是规模问题。如果一个控制器中有很多不同的路由,或者如果你只有多个控制器,那么就很难保持干净和易于理解。控制器不应该比显示传入请求如何路由和返回所需的更多。其他所有重要的东西都应该传递给中间件服务。因此,如果您想要增长空间,第二个选项往往效果更好。

    此外,通过将所有验证逻辑放在一起,您可以轻松地在适用的情况下重用代码。

    如果这是非常静态的并且您不希望添加新的路由或控制器,则选项 1 可以解决。

    【讨论】:

      猜你喜欢
      • 2021-05-07
      • 2015-10-20
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      相关资源
      最近更新 更多