joi 参数验证_如何选择要使用的验证器:Joi和express-validator之间的比较

呼延高超
2023-12-01

joi 参数验证

Imagine you have an e-commerce website and you’re allowing users to create accounts using their name and email. You want to make sure they sign up with real names, not something like cool_dud3.

假设您有一个电子商务网站,并且允许用户使用其名称和电子邮件创建帐户。 您要确保他们使用真实姓名注册,而不要使用cool_dud3之类的名称。

That's where we use validation to validate inputs and make sure input data follows certain rules.

那是我们使用验证来验证输入并确保输入数据遵循某些规则的地方。

In the market, we already have a bunch of validation libraries, but I will compare two important validation libraries: Joi and express-validator for express.js based applications.

在市场上,我们已经有很多验证库,但是我将比较两个重要的验证库: Joi基于express.js的应用程序的 express-validator

This comparison is useful when you have decided to use external input validation library for your application built on expressjs and are somewhat not sure which one to use.

当您决定对构建在expressjs上的应用程序使用外部输入验证库,并且不确定使用哪个输入验证库时,此比较很有用。

谁啊 (Who is what?)

i (Joi)

Joi allows you to create blueprints or schemas for JavaScript objects (an object that stores information) to ensure validation of key information.

Joi允许您为JavaScript对象(存储信息的对象)创建蓝图架构 ,以确保验证关键信息。

快速验证器 (Express-validator)

express-validator is a set of express.js middlewares that wraps validator.js validator and sanitizer functions.

express-validator是一组express.js中间件,其中包装了validator.js验证器和消毒器功能。

So by definition, we can say that:

因此,根据定义,我们可以这样说:

  • Joi can be used for creating schemas (just like we use mongoose for creating NoSQL schemas) and you can use it with plain Javascript objects. It's like a plug n play library and is easy to use.

    Joi可用于创建架构(就像我们使用猫鼬创建NoSQL架构一样),并且您可以将其与普通Javascript对象一起使用。 它就像一个即插即用库,并且易于使用。
  • On the other hand, express-validator uses validator.js to validate expressjs routes, and it's mainly built for express.js applications. This makes this library more niche and provides out of box custom validation and sanitization. Also, I find it easy to understand personally :)

    另一方面, express-validator使用validator.js来验证expressjs路由,它主要是为express.js应用程序构建的。 这使该库更具优势,并提供了开箱即用的自定义验证和清理功能。 另外,我觉得很容易亲自理解:)

Too many methods and API's for doing certain validation in Joi might make you feel overwhelmed so you might end up closing the tab.

在Joi中执行某些验证的方法和API太多,可能会让您感到不知所措,因此最终可能会关闭选项卡。

But I may be wrong — so let’s keep opinions aside and compare both libraries.

但是我可能是错的,所以让我们把意见放在一边,比较两个库。

实例化 (Instantiation)

i (Joi)

In Joi, you need to use Joi.object() to instantiate a Joi schema object to work with.

Joi 您需要使用Joi.object() 实例化要使用的Joi模式对象。

All schemas require Joi.object()to process validation and other Joi features.

所有模式都需要Joi.object()来处理验证和其他Joi功能。

You need to separately read req.body , req.params , req.query to request body, params, and query.

您需要分别阅读req.bodyreq.paramsreq.query来请求主体,参数和查询。

const Joi = require('joi');

const schema = Joi.object().keys({
   // validate fields here
})

快速验证器 (Express-validator)

You can just require express-validator and start using its methods. You don't need to read values from req.body , req.params , and req.query separately.

您可以只需要express-validator 开始使用其方法。 您不需要分别从req.bodyreq.paramsreq.query读取值。

You just need to use the param, query, body methods below to validate inputs respectively as you can see here:

您只需要使用下面的param, query, body方法来分别验证输入,如您在此处看到的:

const {
  param, query, cookies, header 
  body, validationResult } = require('express-validator/check')

app.post('/user', [   
    
// validate fields here
 
], (req, res) => {
const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

必填项 (Field is required)

Let’s take a very basic example where we want to make sure that a username should be required string and is alphaNumeric with min and max characters.

让我们举一个非常基本的示例,在此示例中,我们要确保username应为必需的string并且为带有minmax字符的alphaNumeric

  • Joi:

    乔:

const Joi = require('joi');
const schema = Joi.object().keys({
    username: Joi.string().alphanum().min(3).max(30).required()
})

app.post('/user', (req, res, next) => {   
  const result = Joi.validate(req.body, schema)
  if (result.error) {
    return res.status(400).json({ error: result.error });
  }
});
  • Express-validator

    快速验证器

const { body, validationResult } = require('express-validator/check')

app.post('/user', [   
 body('username')
  .isString()
  .isAlphanumeric()
  .isLength({min: 3, max: 30})
  .exists(), 
], (req, res) => {
  const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

消毒 (Sanitization)

Sanitization is basically checking input to make sure it's free of noise, for example, we all have used .trim() on string to remove spaces.

清理基本上是检查输入以确保没有噪音,例如,我们都在字符串上使用.trim()来删除空格。

Or if you have faced a situation where a number is coming in as "1" so in those cases, we want to sanitize and convert the type during runtime.

或者,如果您遇到数字以"1"输入的情况,那么在这种情况下,我们希望在运行时清理并转换类型。

Sadly, Joi doesn’t provide sanitization out of the box but express-validator does.

可悲的是,Joi没有提供开箱即用的消毒功能,但是express-validator提供了。

示例:转换为MongoDB的ObjectID (Example: converting to MongoDB’s ObjectID)

const { sanitizeParam } = require('express-validator/filter');  

app.post('/object/:id',  
   sanitizeParam('id')
  .customSanitizer(value => {
     return ObjectId(value); 
}), (req, res) => {   // Handle the request });

自定义验证 (Custom Validation)

Joi: .extend( extension ) (Joi: .extend(extension))

This creates a new Joi instance customized with the extension(s) you provide included.

这将创建一个新的Joi实例,并使用您提供的扩展名对其进行自定义。

The extension makes use of some common structures that need to be described first:

该扩展利用了一些需要首先描述的常见结构:

  • value - the value being processed by Joi.

    value -Joi正在处理的值。

  • state - an object containing the current context of validation.

    state -包含验证的当前上下文的对象。

  • key - the key of the current value.

    key当前值的键。

  • path - the full path of the current value.

    path当前值的完整路径。

  • parent - the potential parent of the current value.

    parent当前值的潜在父级。

  • options - options object provided through any().options() or Joi.validate().

    options通过any().options()Joi.validate()提供的选项对象。

延期 (Extension)

extension can be:

extension可以是:

  • a single extension object

    一个扩展对象
  • a factory function generating an extension object

    生成扩展对象的工厂函数
  • or an array of those

    或一系列

Extension objects use the following parameters:

扩展对象使用以下参数:

  • name - name of the new type you are defining, this can be an existing type. Required.

    name您正在定义的新类型的名称,可以是现有类型。 需要。

  • base - an existing Joi schema to base your type on. Defaults to Joi.any().

    base -现有穰架构基础上的类型。 默认为Joi.any()

  • coerce - an optional function that runs before the base, usually serves when you want to coerce values of a different type than your base. It takes 3 arguments value, state and options.

    coerce -在基数之前运行的可选函数,通常在您要强制转换与基数不同类型的值时使用。 它需要3个参数valuestateoptions

  • pre - an optional function that runs first in the validation chain, usually serves when you need to cast values. It takes 3 arguments value, state and options.

    pre在验证链中首先运行的可选函数,通常在需要强制转换值时使用。 它需要3个参数valuestateoptions

  • language - an optional object to add error definitions. Every key will be prefixed by the type name.

    language -添加错误定义的可选对象。 每个键都将以类型名称作为前缀。

  • describe - an optional function taking the fully formed description to post-process it.

    describe一个可选功能,采用完整的描述对其进行后处理。

  • rules - an optional array of rules to add.

    rules要添加的可选规则数组。

  • name - name of the new rule. Required.

    name -新规则的名称。 需要。

  • params - an optional object containing Joi schemas of each parameter ordered. You can also pass a single Joi schema as long as it is a Joi.object(). Of course some methods such as pattern or rename won't be useful or won't work at all in this given context.

    params包含每个有序参数的Joi模式的可选对象。 您也可以传递单个Joi模式,只要它是Joi.object() 。 当然,在这种情况下,诸如patternrename将无用或根本无法工作。

  • setup - an optional function that takes an object with the provided parameters to allow for internal manipulation of the schema when a rule is set. You can optionally return a new Joi schema that will be taken as the new schema instance. At least one of either setup or validate must be provided.

    setup -一个可选功能,该功能接受带有提供的参数的对象,以便在设置规则时对架构进行内部操作。 您可以选择返回一个新的Joi模式,该模式将作为新的模式实例。 必须至少提供setupvalidate之一。

  • validate - an optional function to validate values that takes 4 parameters params, value, state and options. At least one of setup or validate must be provided.

    validate验证值的可选功能,它采用4个参数paramsvaluestateoptions 。 必须至少提供setupvalidate之一。

  • description - an optional string or function taking the parameters as an argument to describe what the rule is doing.

    description一个可选的字符串或函数,将参数作为参数来描述规则的作用。

Example:

范例

joi.extend((joi) => ({
    base: joi.object().keys({
        name: joi.string(),
        age: joi.number(),
        adult: joi.bool().optional(),
    }),
    name: 'person',
    language: {
        adult: 'needs to be an adult',
    },
rules: [
        {
            name: 'adult',
            validate(params, value, state, options) {

                if (!value.adult) {
                    // Generate an error, state and options need to be passed
                    return this.createError('person.adult', {}, state, options);
                }

                return value; // Everything is OK
            }
        }
    ]
})

快速验证器 (Express-validator)

A custom validator may be implemented by using the chain method .custom(). It takes a validator function.

可以使用链方法.custom()实现自定义验证器。 它具有验证器功能。

Custom validators may return Promises to indicate an async validation (which will be awaited upon), or throw any value/reject a promise to use a custom error message.

定制验证器可以返回Promises来指示异步验证(将等待),或者throw任何值/拒绝使用定制错误消息的承诺。

const {
  param, query, cookies, header 
  body, validationResult } = require('express-validator/check')

app.get('/user/:userId', [   
 param('userId')
  .exists()
  .isMongoId()
  .custom(val => UserSchema.isValidUser(val)), 
], (req, res) => {
    
const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

条件验证 (Conditional Validation)

express-validator does not support conditional validation as of now, but there is a PR for that already you can check https://github.com/express-validator/express-validator/pull/658

express-validator到目前为止不支持条件验证,但是已经有一个PR可以检查https://github.com/express-validator/express-validator/pull/658

Let’s see how it works in Joi:

让我们看看它在Joi中如何工作:

any.when(condition, options) (any.when(condition, options))

any: Generates a schema object that matches any data type.

any: 生成与任何数据类型匹配的架构对象。

const schema = Joi.object({
    a: Joi.any().valid('x'),
    b: Joi.any()
}).when(
    Joi.object({ b: Joi.exist() })
    .unknown(), {
    then: Joi.object({
        a: Joi.valid('y')
    }),
    otherwise: Joi.object({
        a: Joi.valid('z')
    })
});

alternatives.when(condition, options) (alternatives.when(condition, options))

Adds a conditional alternative schema type, either based on another key (not the same as any.when()) value, or a schema peeking into the current value, where:

添加基于其他键(与any.when() )的条件替代模式类型,或基于当前值的模式,其中:

  • condition - the key name or reference, or a schema.

    condition键名或引用或模式。

  • options - an object with:

    options具有以下内容的对象:

  • is - the required condition joi type. Forbidden when condition is a schema.

    is -所需条件joi类型。 condition为架构时禁止使用。

  • then - the alternative schema type to try if the condition is true. Required if otherwise is missing.

    then -替代架构类型尝试,如果条件为真。 如果需要的话otherwise丢失。

  • otherwise - the alternative schema type to try if the condition is false. Required if then is missing.

    otherwise -如果条件为false,则尝试使用的替代模式类型。 如果需要, then丢失。

const schema = Joi
     .alternatives()
     .when(Joi.object({ b: 5 }).unknown(), {
        then: Joi.object({
           a: Joi.string(),
           b: Joi.any()
      }),
      otherwise: Joi.object({
        a: Joi.number(),
        b: Joi.any()
      })
});

嵌套验证 (Nested Validation)

When you want to validate an array of objects/items or just object keys

当您要验证对象/项目数组或仅验证对象键时

Both libraries support nested validation

两个库均支持嵌套验证

Now what about express-validator?

现在,快递验证器怎么样?

通配符 (Wildcards)

Wildcards allow you to iterate over an array of items or object keys and validate each item or its properties.

通配符使您可以遍历项目或对象键的数组,并验证每个项目或其属性。

The * character is also known as a wildcard.

*字符也称为通配符。

const express = require('express'); 
const { check } = require('express-validator/check'); 
const { sanitize } = require('express-validator/filter');  
const app = express(); 

app.use(express.json());  
app.post('/addresses', [   
    check('addresses.*.postalCode').isPostalCode(),
    sanitize('addresses.*.number').toInt() 
], 
(req, res) => {   // Handle the request });

Joi

i

const schema = Joi.object().keys({
    addresses: Joi.array().items(
        Joi.object().keys({
            postalCode: Joi.string().required(),
        }),
    )
});

自定义错误消息 (Custom Error Messages)

i (Joi)

any.error(err, [options]) (any.error(err, [options]))

Overrides the default joi error with a custom error

用自定义错误覆盖默认的joi错误

let schema = Joi.string().error(new Error('Was REALLY expecting a string'));

快速验证器 (Express-validator)

const { check } = require('express-validator/check'); 

app.post('/user', [   
   // ...some other validations...   
   check('password')     
   .isLength({ min: 5 }).withMessage('must be at 5 chars long')
   .matches(/\d/).withMessage('must contain a number') 
], 
(req, res) => {   // Handle the request somehow });

结论 (Conclusion)

I covered the most important parts of both libraries and you can decide yourself which one you want to use. Please let me know in the comments below if I left out anything important in the comparison.

我介绍了这两个库的最重要部分,您可以自己决定要使用哪一个。 如果我在比较中遗漏了任何重要内容,请在下面的评论中让我知道。

I hope you find it helpful when deciding the next input validation module for your express.js application.

希望为您的express.js应用程序确定下一个输入验证模块时,它会有所帮助。

I wrote an in-depth article on it here: how to validate inputs. Do check it out.

我在这里写了一篇深入的文章: 如何验证输入 。 请检查一下。

Don’t hesitate to clap if you considered this a worthwhile read!

如果您认为这值得一读,请随时鼓掌!

Originally published at 101node.io on March 31, 2019.

最初于2019年3月31日发布在101node.io

翻译自: https://www.freecodecamp.org/news/how-to-choose-which-validator-to-use-a-comparison-between-joi-express-validator-ac0b910c1a8c/

joi 参数验证

 类似资料: