## @e22m4u/js-data-schema JavaScript модуль для работы со схемой данных. ## Содержание - [Установка](#установка) - [Схема данных](#схема-данных) - [Проверка данных](#проверка-данных) - [Парсинг данных](#парсинг-данных) - [Именованные схемы](#именованные-схемы) - [Пустые значения](#пустые-значения) - [Тесты](#тесты) - [Лицензия](#лицензия) ## Установка ```bash npm install @e22m4u/js-data-schema ``` Модуль поддерживает ESM и CommonJS стандарты. *ESM* ```js import {DataValidator} from '@e22m4u/js-data-schema'; ``` *CommonJS* ```js const {DataValidator} = require('@e22m4u/js-data-schema'); ``` ## Схема данных Схема данных позволяет указать допустимый тип значения, схему элементов массива и схему свойств объекта. Схему можно использовать для проверки входящих данных или для преобразования данных к формату схемы. Свойства схемы: - `type` тип данных (допускает [пустые значения](#пустые-значения)); - `items` схема элементов массива, фабрика или имя схемы; - `properties` схема свойств объекта, фабрика или имя схемы; - `required` исключает *пустые значения*; - `default` значение по умолчанию или фабрика; #### type Параметр `type` определяет тип данных. При определении типа можно использовать константу или название типа в виде строки. Константы проверяются редакторами кода, что позволяет избежать опечаток при вводе типа. | константа | значение | |--------------------|-------------| | `DataType.ANY` | `"any"` | | `DataType.STRING` | `"string"` | | `DataType.NUMBER` | `"number"` | | `DataType.BOOLEAN` | `"boolean"` | | `DataType.ARRAY` | `"array"` | | `DataType.OBJECT` | `"object"` | #### items Параметр `items` позволяет указать схему для элементов массива. Параметр можно использовать только если явно указан тип `array`. В примере ниже схема массива включает описание его элементов, которые должны соответствовать числовому типу. ```js { type: DataType.ARRAY, // тип данных items: { type: DataType.NUMBER // тип элементов } } // [-1, 0, 1, undefined, null] ``` Так как типы допускают [пустые значения](#пустые-значения), рекомендуется использовать параметр `required` в определении схемы элемента, чтобы исключить такие значения из состава массива. ```js { type: DataType.ARRAY, items: { type: DataType.NUMBER, required: true // исключает undefined, null и 0 } } // [-1, 1] ``` #### properties Параметр `properties` позволяет указать схему каждого свойства объекта. Параметр можно использовать, только если явно указан тип `object`. В примере ниже используется схема объекта с двумя свойствами. ```js { type: DataType.OBJECT, // тип данных properties: { name: { type: DataType.STRING // тип свойства "name" }, age: { type: DataType.NUMBER // тип свойства "age" } } } // { // "name": "John", // "age": 27 // } ``` Значения свойств могут быть обязательными. Для этого используется параметр `required` в схеме соответствующего свойства. Если параметр указан, то [пустые значения](#пустые-значения) будут вызывать ошибку при проверке свойства. ```js { type: DataType.OBJECT, properties: { name: { type: DataType.STRING, required: true // исключает undefined, null и "" }, age: { type: DataType.NUMBER, required: true // исключает undefined, null и 0 } } } ``` #### required Так как по умолчанию все типы допускают [пустые значения](#пустые-значения), параметр `required` может быть полезен для явного их запрета при проверке данных. Параметр можно использовать там, где указывается тип данных. ```js { type: DataType.STRING, // тип данных required: true // исключает пустые значения } // "foo", "bar" ... ``` #### default Значение по умолчанию можно указать в параметре `default`. Указанное значение будет использовано, если исходное значение оказалось [пустым](#пустые-значения). Если значение параметра является объектом или массивом, то итоговые данных получат его копию. ```js { type: DataType.STRING, // тип данных default: 'N/A' // значение по умолчанию } ``` ## Проверка данных Модуль экспортирует сервис `DataValidator`, с помощью которого выполняется проверка соответствия данных указанной схеме. Пример ниже демонстрирует создание экземпляра сервиса и проверку примитивных значений. ```js import {DataValidator, DataType} from '@e22m4u/js-data-schema'; const validator = new DataValidator(); const numberSchema = {type: DataType.NUMBER}; // OK validator.validate(10, numberSchema); validator.validate(0, numberSchema); validator.validate(undefined, numberSchema); validator.validate(null, numberSchema); // выбросит DataValidationError validator.validate('str', numberSchema); validator.validate(true, numberSchema); validator.validate([1, 2, 3], numberSchema); validator.validate({foo: 'bar'}, numberSchema); ``` Каждый тип данных имеет собственный набор [пустых значений](#пустые-значения), которые являются допустимыми при проверке соответствующего типа. Чтобы исключить такие значения применяется параметр `required`. ```js import {DataValidator, DataType} from '@e22m4u/js-data-schema'; const validator = new DataValidator(); const requiredNumberSchema = { type: DataType.NUMBER, required: true // исключает пустые значения }; // OK validator.validate(10, requiredNumberSchema); validator.validate(-10, requiredNumberSchema); // выбросит DataValidationError validator.validate(0, requiredNumberSchema); validator.validate(undefined, requiredNumberSchema); validator.validate(null, requiredNumberSchema); ``` ## Парсинг данных Сервис `DataParser` спроектирован для приведения данных в соответствие указанной схеме. Приведение выполняется с учетом возможных ошибок пользовательского ввода. К примеру, если схема ожидает число, но входящие данные содержат другие символы, то будет выброшена ошибка. ```js import {DataParser, DataType} from '@e22m4u/js-data-schema'; const parser = new DataParser(); parser.parse('10', {type: DataType.NUMBER}); // 10 parser.parse('10.5', {type: DataType.NUMBER}); // 10.5 parser.parse('10abc', {type: DataType.NUMBER}); // DataParsingError ``` Массивы и объекты могут быть представлены в виде *JSON*. Метод `parse` поддерживает данный формат и выполняет проверку разобранного значения. К примеру, если элементы массива не соответствуют определению схемы, то будет выброшена ошибка. ```js import {DataParser, DataType} from '@e22m4u/js-data-schema'; const parser = new DataParser(); const numberListSchema = { type: DataType.ARRAY, items: { type: DataType.NUMBER, required: true, // исключает undefined, null и 0 }, }; parser.parse('[1, 2, 3]', numberListSchema); // [1, 2, 3] parser.parse('[1, 2, null]', numberListSchema); // DataParsingError ``` Если при разборе данных значение оказалось [пустым](#пустые-значения), то при наличии параметра `default` используется значение по умолчанию. Значение данного параметра должно соответствовать схеме. ```js import {DataParser, DataType} from '@e22m4u/js-data-schema'; const parser = new DataParser(); const schema = { type: DataType.NUMBER, default: 0, }; parser.parse('10', schema); // 10 parser.parse(undefined, schema); // 0 parser.parse('N/A', schema); // DataParsingError ``` ## Именованные схемы Модуль экспортирует сервисы для проверки и парсинга данных. Каждый сервис позволяет регистрировать схемы данных по уникальному имени методом `defineSchema`. ```js import {DataValidator, DataParser, DataType} from '@e22m4u/js-data-service'; const validator = new DataValidator(); const parser = new DataParser(); const schema = { type: DataType.ARRAY, items: { type: DataType.STRING, required: true, }, }; validator.defineSchema({name: 'mySchema', schema}); parser.defineSchema({name: 'mySchema', schema}); ``` Регистрация схем может выполняться централизованно через реестр. Этого можно добиться используя сервис-контейнер, который выступает в роли точки входа. ```js import {ServiceContainer} from '@e22m4u/js-service'; import { DataType, DataParser, DataValidator, DataSchemaRegistry, } from '@e22m4u/js-data-service'; const app = new ServiceContainer(); const registry = app.get(DataSchemaRegistry); registry.defineSchema({ name: 'mySchema', schema: { type: DataType.ARRAY, items: { type: DataType.STRING, required: true, }, }, }); const validator = app.get(DataValidator); const parser = app.get(DataParser); ``` В примере выше оба сервиса используют общий реестр и знают о зарегистрированной схеме `mySchema`, что избавляет от необходимости синхронизации между сервисами данного модуля. #### Использование именованных схем Зарегистрированное имя схемы можно использовать вместо объекта схемы. Пример ниже демонстрирует проверку данных с помощью именованной схемы. ```js validator.defineSchema({ name: 'stringList', schema: { type: DataType.STRING, required: true, }, }); validator.validate(['a', 'b', 'c'], 'mySchema'); // OK validator.validate(['a', 'b', 10], 'mySchema'); // DataValidationError ``` Зарегистрированные имена можно встраивать в другие схемы. Ниже приводится пример использования именованной схемы для определения структуры элементов массива. ```js parser.defineSchema({ name: 'user', // имя схемы schema: { type: DataType.OBJECT, properties: { name: { type: DataType.STRING, required: true, }, age: { type: DataType.NUMBER, default: 0, }, }, }, }); const jsonData = `[{"name": "John","age": 35},{"name": "Tommy"}]`; const users = parser.parse(jsonData, { type: DataType.ARRAY, items: 'user', // <= именованная схема }); console.log(users); // [ // { // name: 'John', // age: 35 // }, // { // name: 'Tommy', // age: 0 // } // ] ``` Если именованная схема описывает объект, то допускается передача имени схемы в параметр `properties`, что позволяет переопределить остальные параметры зарегистрированной схемы. ```js validator.validate(data, { type: DataType.OBJECT, properties: 'user', // имя схема вместо схемы свойств required: true, // переопределение параметра схемы "user" }); ``` ## Пустые значения Разные типы данных имеют свои наборы пустых значений. Эти наборы используются для определения наличия полезной нагрузки в значении свойства. Например, параметр `required` исключает пустые значения при проверке данных. | тип данных | пустые значения | |--------------------|----------------------------| | `DataType.ANY` | *значения остальных типов* | | `DataType.STRING` | `undefined`, `null`, `""` | | `DataType.NUMBER` | `undefined`, `null`, `0` | | `DataType.BOOLEAN` | `undefined`, `null` | | `DataType.ARRAY` | `undefined`, `null`, `[]` | | `DataType.OBJECT` | `undefined`, `null`, `{}` | Управление этими наборами осуществляется через специальный сервис, который предоставляет модуль [@e22m4u/js-empty-values](https://www.npmjs.com/package/@e22m4u/js-empty-values) (не требует установки). ## Тесты ```bash npm run test ``` ## Лицензия MIT