gpt4 book ai didi

node.js - 我应该将验证放在 Node 模型内部吗?

转载 作者:太空宇宙 更新时间:2023-11-04 03:15:49 25 4
gpt4 key购买 nike

在我的应用程序中,我的用户模型如下。当我验证确认密码时, Mongoose 模型中存在一些业务逻辑部分。我怎样才能以更好的方式表达这个?我应该将验证部分与模型分开吗?或者我应该将验证保留在 Mongoose 模型中?

import Joi from 'joi';
import { Schema, model } from 'mongoose';

const userSchema = new Schema(
{
firstName: {
type: String,
required: true,
minlength: 2,
maxlength: 30,
},
lastName: {
type: String,
required: true,
minlength: 2,
maxlength: 30,
},
email: {
type: String,
required: true,
minlength: 5,
maxlength: 100,
unique: true,
lowercase: true
},
password: {
type: String,
required: true,
minlength: 8,
maxlength: 1024,
},
avatar: {
type: String
},
},
);

export const User = model('User', userSchema);

/** Validate user */
export function validateUser(user) {
const schema = {
firstName: Joi.string().min(2).max(30).required(),
lastName: Joi.string().min(2).max(30).required(),
email: Joi.string().min(5).max(100).required().email(),
password: Joi.string().min(8).max(1024).required(),
confirmPassword: Joi.any().valid(Joi.ref('password')).required().options({ language: { any: { allowOnly: 'Passwords do not match' } } }),
avatar: Joi.string(),
};

return Joi.validate(user, schema, { abortEarly: false });
}

/** Validate login */
export function validateLogin(login) {
const schema = {
email: Joi.string().min(5).max(255).required().email(),
password: Joi.string().min(5).max(255).required()
};

return Joi.validate(login, schema);
}

最佳答案

也许你应该尝试询问CodeReview ,因为它更多的是设计而不是问题。

无论如何,这是我的意见(因为,既然是设计,这主要是一个意见问题)。

1。使用 Mongoose 仅​​声明与数据库相关的验证

我不会使用 Mongoose 来验证与对象相关的约束。

在您的示例中,Mongoose 只会声明强制 typeunique,因为它要求数据库为此属性建立索引(通过扩展,indexsparse)。

2。使用 Joi(又名业务逻辑)验证其他所有内容

仅仅因为 Joi 的目的是验证对象,因此它显然比 Mongoose 的功能更好、更容易处理。

在您的示例中,Mongoose 不需要(双重)检查 minlengthmaxlength,因为 Joi 已经这样做了 - 前提是您正确控制了数据库的入口点。 小写也可以是 handled by Joi 。这些对 Mongo 存储数据的方式没有影响,它是纯粹的业务,就像 password/confirmPassword 相等性检查一样。

(顺便说一句,您还可以 .strip() 这个 confirmPassword 属性以避免在请求处理程序中执行此操作)

3。保持每个实体的 Joi 模式接近 Mongoose 模式

我不会公开验证实体的函数,而是公开 POST 和 PUT 模式。在大多数情况下,您可以自动从 POST 派生 PUT(毕竟只需添加 ID),但具有密码确认的用户是需要区分的典型示例。

这样,您就可以在这里构建几乎通用的经典 REST API:使用文件/模块获取路由名称,根据使用的 HTTP 方法尝试其公开的验证,然后使用其公开的模型来执行持久性工作。然后,您还可以考虑使授权变得通用,如果您的数据模型在 session 中阐明用户,这将在实体上创建一个完全通用的 API,但这是另一个故事了。

将 Mongoose 和 Joi 模式保留在同一个文件中还可以让开发人员(以及您,在 6 个月内,当您忘记如何编码时)快速了解必须如何使用特定实体。这意味着,当有人开发将数据插入数据库的 CLI 脚本时,他们将在附近使用验证模式,如果他们“忘记”使用它,您可以责怪他们:同样,控制数据库的入口点。 ;)

4。不要过度验证,或者在处理特定业务的地方进行

我希望我的实体文件保持为实体文件。

您公开了一种验证登录的方法,但是您知道无法插入不符合 Joi 和 Mongoose 架构的内容。因此,如果有人想要使用 1500 个字符长的电子邮件登录,请让他们:它最终会成为正常拒绝的登录,因为数据库中没有任何内容匹配。但这并不意味着您无法实现 UI 验证,但这也意味着只要架构发生更改就需要调整 UI 代码。

但从更一般的角度来看,登录确实不是一个正常的、可能通用的端点。这些是您可能需要特殊验证步骤的唯一情况(据我所知)。由于这些路由完全与业务相关,因此您需要手工制作它们,这就是我放置这些特殊(也与业务相关)验证步骤的地方。无论如何,不在“最相关的”实体中。

以下是我的用户实体文件中的内容:

import Joi from 'joi';
import { Schema, model } from 'mongoose';

// purely DB stuff
export default model('User', new Schema(
{
firstName: { type: String },
lastName: { type: String },
email: { type: String, unique: true },
password: { type: String },
avatar: { type: String }
}
));

// purely business stuff
// common schema first
const schema = {
firstName: Joi.string().min(2).max(30).required(),
lastName: Joi.string().min(2).max(30).required(),
email: Joi.string().min(5).max(100).required().lowercase().email(),
password: Joi.string().min(8).max(1024),
avatar: Joi.string(),
};

// POST-specific case
const post = {
...schema,
// note that for this particular case, a UI check is enough
confirmPassword: Joi.string().valid(Joi.ref('password')).required()
.options({ language: { any: { allowOnly: 'Passwords do not match' } } })
.strip()
};
// password is only required on registration
post.password = post.password.required();

// PUT-specific case
const put = {
...schema,
id: Joi.string().required()
};

// you may also want to use a derived Joi schema on GET output to strip some data like password
export const joi = { post, put };

关于node.js - 我应该将验证放在 Node 模型内部吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56517185/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com