Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
{ age: [ 'positive_integer', {default: 18} ] }
{
name: 'required',
}
{
name: 'REQUIRED',
}
{
name: 'REQUIRED',
}
{
name: 'required',
}
{
name: '',
}
{
name: 'REQUIRED',
}
my $default_rules = Validator::LIVR->ger_default_rules();
while ( my ($rule_name, $rule_builder) = each %$default_rules ) {
Validator::LIVR->register_default_rules($rule_name => sub {
my $rule_validator = $rule_builder->(@_);
return sub {
my $error = $rule_validator->(@_);
die $error if $error;
return;
}
});
}
целиком поддерживаю идею декларативной валидации, функциональщина в этом деле, на мой взгляд — зло.
likeВам не кажется, что в таком виде это просто не имеет смысла? Декларируется независимость от языка, но регулярки везде разные, никакого «common syntax» по сути нет, даже в самых тривиальных вещах где-то пишут «a+» а где-то «a\+». Не лучше ли в спеке однозначно объявить что синтаксис регулярок должен быть, например, PCRE?
…
Be aware that regular expressions can be language dependent. Try to use most common syntax.
var LIVR = require('livr');
var requiredIfFieldEmpty = function(field) {
return function(value, fields) {
var isDependentFieldEmpty = fields[field] === null || fields[field] === undefined || fields[field] === '';
var isTargetFieldEmpty = value === null || value === undefined || value === '';
if (isDependentFieldEmpty && isTargetFieldEmpty) {
return 'REQUIRED'
}
}
};
LIVR.Validator.registerDefaultRules({ required_if_field_empty: requiredIfFieldEmpty});
var validator = new LIVR.Validator({
phone: {required_if_field_empty: 'email'},
email: {required_if_field_empty: 'phone'},
});
Попробуйте описать этот пример на JSON Schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"order_id": {
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true
},
"product_ids": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true
}
}
},
"required": ["order_id", "product_ids"]
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"definitions": {
"positiveInteger": {
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true
}
},
"properties": {
"order_id": { "$ref": "#/definitions/positiveInteger" },
"product_ids": {
"type": "array",
"items": { "$ref": "#/definitions/positiveInteger" }
}
},
"required": ["order_id", "product_ids"]
}
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for an fstab entry",
"type": "object",
"required": [ "storage" ],
"properties": {
"storage": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/diskDevice" },
{ "$ref": "#/definitions/diskUUID" },
{ "$ref": "#/definitions/nfs" },
{ "$ref": "#/definitions/tmpfs" }
]
},
"fstype": {
"enum": [ "ext3", "ext4", "btrfs" ]
},
"options": {
"type": "array",
"minItems": 1,
"items": { "type": "string" },
"uniqueItems": true
},
"readonly": { "type": "boolean" }
},
"definitions": {
"diskDevice": {
"properties": {
"type": { "enum": [ "disk" ] },
"device": {
"type": "string",
"pattern": "^/dev/[^/]+(/[^/]+)*$"
}
},
"required": [ "type", "device" ],
"additionalProperties": false
},
"diskUUID": {
"properties": {
"type": { "enum": [ "disk" ] },
"label": {
"type": "string",
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
}
},
"required": [ "type", "label" ],
"additionalProperties": false
},
"nfs": {
"properties": {
"type": { "enum": [ "nfs" ] },
"remotePath": {
"type": "string",
"pattern": "^(/[^/]+)+$"
},
"server": {
"type": "string",
"oneOf": [
{ "format": "host-name" },
{ "format": "ipv4" },
{ "format": "ipv6" }
]
}
},
"required": [ "type", "server", "remotePath" ],
"additionalProperties": false
},
"tmpfs": {
"properties": {
"type": { "enum": [ "tmpfs" ] },
"sizeInMB": {
"type": "integer",
"minimum": 16,
"maximum": 512
}
},
"required": [ "type", "sizeInMB" ],
"additionalProperties": false
}
}
}
{
order_id: ['required', 'positive_integer'],
product_ids: [{
'list_of': [ 'required', 'positive_integer' ]
}]
}
Как описываются правила валиции? Каждое правило состоит из имени и аргументов (практически, как вызов функции) и в общем случае описывается следующим образом {«RULE_NAME»: ARRAY_OF_ARGUMENTS}. Для каждого поля описывается массив правил, которые применяются в порядке следования.
Проблема №1. Многие валидаторы проверяют только те данные, для которых описаны правила проверки. Для меня важно, чтобы любой пользовательский ввод, который явно не разрешен, был проигнорирован. То есть, валидатор должен вырезать все данные для которых не описаны правила валидации. Это просто фундаментально требование.
{
order_id: ['required', 'positive_integer'],
product_ids: [{
'list_of': [ 'required', 'positive_integer' ]
}]
}
мне кажется, из-за такой лаконичности какие-то сложные схемы будет трудно или невозможно описать на LIVR
Например, в json-schema для чисел есть проверка на делимость (multipleOf)
Ещё в схеме есть patternProperties, позволяющий проверять имя ключа по регулярке, это порой бывает нужно
для строк — regexp
Можно также вынести все свои типы в какой-то отдельный файл, а и через $ref их использовать
В целом, для простых схем LIVR хорош, но сложные — пока что не его конёк.
Это похоже на "Выстрел дробью". Поддерживать потом такой набор правил...
С таким доходом есть ряд проблем:
Кроме того, можно сделать функцию типа applyCommonRules(livr, commonRules) и просто преобразовывать один формат в другой. Мощь LIVR в том, что это просто структура данных и можно делать с этими данными любые операции. Написать такую функцию займет полчаса времени и позволит увидеть в реальном проекте нужно ли это на уровне спецификации или может быть просто сторонней библиотекой (ну и ее можно зарелизить в opensource)
LIVR — «независимые от языка правила валидации» или валидация данных без «проблем»