【问题标题】:Validate uniqueness in node.js with Joi使用 Joi 在 node.js 中验证唯一性
【发布时间】:2023-02-15 08:58:54
【问题描述】:

如何在 Joi 包的帮助下检查传入的请求值是否唯一。

exports.createUser = {
  body: Joi.object().keys({
    email: Joi.string().required().email(),
    password: Joi.string().required().custom(password),
    phoneNumber: Joi.string().min(10).required(),
  }),
};

在这里我想检查电子邮件是否是唯一的。我知道我可以在 mongoose(Schema) 中做到这一点,但我想用 joi 包来做到这一点。

API端点:

router
  .route("/register")
  .post(validate(userValidation.createUser), User.register);

注册控制器:

exports.register = catchAsync(async (req, res) => {
  try {
    var isValidated = await userService.validateInDatabase(req);
    if (!isValidated)
      return res
        .status(409)
        .json({ error: "Phone number or email is already registered" });

    var user = await userService.create(req.body);
    var token = await sendVerification(user);
    return res.status(201).json({ user, token });
  } catch (error) {
    return res.status(400).json({ message: error });
  }
});

我有一个名为 validateInDatabase 的函数,但我不想使用它。

userService.create服务函数:

exports.create = async (user) => {
  const hashedPassword = passwordHash.generate(user.password);

  let new_user = new User({
    phoneNumber: user.phoneNumber,
    email: user.email,
    password: hashedPassword,
  });

  const payload = {
    id: new_user._id,
  };
  let JWToken = jwt.sign(payload, keys.JWToken, { expiresIn: 31556926 });
  const userData = await new_user.save();
  return { userData, JWToken };
};

验证功能:

const validate = (schema) => (req, res, next) => {
  const validSchema = pick(schema, ["params", "query", "body"]);
  const object = pick(req, Object.keys(validSchema));
  const { value, error } = Joi.compile(validSchema)
    .prefs({ errors: { label: "key" }, abortEarly: false })
    .validate(object);

  if (error) {
    const errorMessage = error.details
      .map((details) => details.message)
      .join(", ");
    return res.status(400).json({ error: errorMessage });
  }
  Object.assign(req, value);
  return next();
};

【问题讨论】:

    标签: node.js express validation unique


    【解决方案1】:

    您可以使用custom(用于同步)或external验证(用于异步)并将电子邮件签入数据库。

    是这样的:

    exports.createUser = {
      body: Joi.object().keys({
        email: Joi.string().required().email().external(async (email) => {
            // You have to create `checkEmailInUse` funciton somewhere in your code and call it here
            const isEmailInUse = await checkEmailInUse(email);
            if(isEmailInUse) {
                throw new Error('email in use');
            }
    
            return email;
        }),
        password: Joi.string().required().custom(password),
        phoneNumber: Joi.string().min(10).required(),
      }),
    };
    

    在这里使用validateAsync而不是validate

    const validate = (schema) => (req, res, next) => {
      const validSchema = pick(schema, ["params", "query", "body"]);
      const object = pick(req, Object.keys(validSchema));
      try {
          const value = await Joi.compile(validSchema)
            .prefs({ errors: { label: "key" }, abortEarly: false })
            .validateAsync(object);
            
          Object.assign(req, value);
          return next();
      }
      catch(error) {
        const errorMessage = error.details
          .map((details) => details.message)
          .join(", ");
        return res.status(400).json({ error: errorMessage });
      }
    };
    

    【讨论】:

    • 我在用户模型文件中创建了一个函数,并按照你所说的调用它,但它抛出了类似Error: Schema with external rules must use validateAsync() 的错误
    • 函数:userSchema.statics.isEmailTaken = async function (email, excludeUserId) { const user = await this.findOne({ email, _id: { $ne: excludeUserId } }); return !!user; };
    • @JohnOliver 你能告诉我你的终点代码吗?
    • @JohnOliver 而不是schema.validate() 现在你必须打电话给schema.validateAsync()
    • 在哪里调用 schema.validateAsync() 因为我的代码中没有任何地方 schema.validate()
    【解决方案2】:

    我建议通过使用 any.external() 进行异步查找。

    这是一个示例 (TypeScript),用于检查用户名是否尚未使用:

        import Joi, { ExternalValidationFunction } from 'joi'
    
        // lookup function
        usernameIsAvailableOrThrow = (
            username: string
        ): Promise<ReturnType<ExternalValidationFunction>> => {
            return isUsernameTaken(username).then((isTaken) => {
                if (isTaken) {
                    throw new Error('This username is already taken')
                }
                return undefined // success for joi validation
            })
        }
    
        // validation definition
        externalValidationObj = Joi.object({
            username: Joi.string().external(usernameIsAvailableOrThrow)
        })
    
        // run validation
        externalValidationObj.validateAsync({ username }).then(() => {
          // success
        })
        .catch(() => {
          // error
        })
    

    【讨论】:

      猜你喜欢
      • 2018-04-13
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      • 1970-01-01
      • 2022-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多