Перейти к основному содержимому

Типизация атрибутов

Схема данных атрибута

Для типизации атрибутов Памир использует схему данных атрибута. Схема данных атрибута — это язык описания структуры и ограничений для данных в формате JSON. Он позволяет определять, как должен выглядеть JSON-документ, какие поля обязательны, какие типы данных допустимы, какие значения могут принимать поля и другие правила валидации.

Схему данных атрибута построена на основе JSON Schema (спецификация 2020-12).

Пример схемы данных атрибута:

{
"type": "string",
"format": "email"
}

type: Определяет тип данных
format: Уточняет формат данных

Типы данных

  1. string:
  • Строка текста.
  • Пример: "Hello, world!".
  1. number:
  • Число с плавающей точкой (включая целые числа).
  • Пример: 42, 3.14.
  1. integer:
  • Целое число.
  • Пример: 42.
  1. boolean:
  • Логическое значение (true или false).
  • Пример: true.
  1. array:
  • Упорядоченный список значений.
  • Пример: [1, 2, 3].
  1. object:
  • Неупорядоченный набор пар ключ-значение.
  • Пример: { "name": "Alice", "age": 30 }.
  1. null:
  • Значение null.
  • Пример: null.

Форматы

  1. date:
  • Дата в формате YYYY-MM-DD.
  • Пример: "2023-10-05".
  1. date-time:
  • Дата и время в формате YYYY-MM-DDTHH:MM:SSZ.
  • Пример: "2023-10-05T14:30:00Z".
  1. email:
  • Адрес электронной почты.
  • Пример: "user@example.com".
  1. hostname:
  • Имя хоста.
  • Пример: "example.com".
  1. ipv4, ipv6:
  • IPv4 или IPv6 адрес.
  • Пример: "192.168.1.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334".
  1. uri:
  • URI (Uniform Resource Identifier).
  • Пример: "https://example.com".
  1. uuid:
  • Уникальный идентификатор (UUID).
  • Пример: "550e8400-e29b-41d4-a716-446655440000".

Тип string

В схеме данных атрибута Памир для типа string существует несколько ключевых слов (keywords), которые позволяют задавать дополнительные ограничения.

  • minLength
    Определяет минимальную длину строки.
    Пример:

    {
    "type": "string",
    "minLength": 5
    }

    Строка должна содержать не менее 5 символов.

  • maxLength
    Определяет максимальную длину строки.
    Пример:

    {
    "type": "string",
    "maxLength": 10
    }

    Строка должна содержать не более 10 символов.

  • pattern
    Задает регулярное выражение, которому должна соответствовать строка.
    Пример:

    {
    "type": "string",
    "pattern": "^[A-Za-z]+$"
    }

    Строка должна состоять только из букв латинского алфавита.

  • format
    Указывает формат строки. Поддерживаемые форматы включают:

    • email (адрес электронной почты)
    • date (дата в формате YYYY-MM-DD)
    • date-time (дата и время в формате ISO 8601)
    • uri (URL)
    • uuid (уникальный идентификатор)
    • hostname (имя хоста)
    • password (пароль)

    Пример:

    {
    "type": "string",
    "format": "email"
    }

    Строка должна быть валидным адресом электронной почты.

  • enum
    Ограничивает строку определенным набором значений.
    Пример:

    {
    "type": "string",
    "enum": ["red", "green", "blue"]
    }

    Строка должна быть одним из значений: "red", "green" или "blue".

  • const
    Указывает, что строка должна быть равна определенному значению.
    Пример:

    {
    "type": "string",
    "const": "active"
    }

    Строка должна быть равна "active".

Пример схемы данных атрибута с использованием нескольких ключевых слов

{
"type": "string",
"minLength": 3,
"maxLength": 20,
"pattern": "^[A-Za-z0-9]+$",
"format": "email"
}

Эта схема требует, чтобы строка:

  • Была длиной от 3 до 20 символов,
  • Состояла только из букв и цифр,
  • Была валидным адресом электронной почты.

Тип number

В схеме данных атрибута Памир существует несколько ключевых слов (keywords), которые позволяют задавать ограничения и правила для числовых данных.

  • minimum
    Определяет минимальное значение числа (включительно).
    Пример:

    {
    "type": "number",
    "minimum": 0
    }

    Число должно быть больше или равно 0.

  • maximum
    Определяет максимальное значение числа (включительно).
    Пример:

    {
    "type": "number",
    "maximum": 100
    }

    Число должно быть меньше или равно 100.

  • exclusiveMinimum
    Определяет минимальное значение числа (исключительно).
    Пример:

    {
    "type": "number",
    "exclusiveMinimum": 0
    }

    Число должно быть строго больше 0.

  • exclusiveMaximum
    Определяет максимальное значение числа (исключительно).
    Пример:

    {
    "type": "number",
    "exclusiveMaximum": 100
    }

    Число должно быть строго меньше 100.

  • multipleOf
    Указывает, что число должно быть кратно заданному значению.
    Пример:

    {
    "type": "number",
    "multipleOf": 2
    }

    Число должно быть четным (кратным 2).

  • enum
    Ограничивает число определенным набором значений.
    Пример:

    {
    "type": "number",
    "enum": [1, 2, 3]
    }

    Число должно быть одним из значений: 1, 2 или 3.

  • const
    Указывает, что число должно быть равно определенному значению.
    Пример:

    {
    "type": "number",
    "const": 42
    }

    Число должно быть равно 42.

Пример JSON Schema с использованием нескольких ключевых слов

{
"type": "number",
"minimum": 0,
"maximum": 100,
"multipleOf": 5
}

Эта схема требует, чтобы число:

  • Было в диапазоне от 0 до 100 (включительно),
  • Было кратно 5 (например, 0, 5, 10, ..., 100).

Пример с exclusiveMinimum и exclusiveMaximum

{
"type": "number",
"exclusiveMinimum": 0,
"exclusiveMaximum": 100
}

Эта схема требует, чтобы число:

  • Было строго больше 0,
  • Было строго меньше 100.

Тип integer

В схеме данных атрибута Памир для типа integer используются те же ключевые слова, что и для типа number, но с учетом того, что integer представляет только целые числа.

Тип boolean

Для типа boolean в схеме данных атрибута Памир ключевых слов меньше, чем для других типов, так как boolean может принимать только два значения: true или false. Однако есть несколько полезных ключевых слов, которые можно использовать для работы с этим типом.

  • enum
    Ограничивает значение boolean определенным набором значений.
    Пример:

    {
    "type": "boolean",
    "enum": [true]
    }

    Значение должно быть true.

  • const
    Указывает, что значение boolean должно быть равно определенному значению.
    Пример:

    {
    "type": "boolean",
    "const": false
    }

    Значение должно быть false.

Пример JSON Schema для типа boolean:

{
"type": "boolean"
}

Эта схема допускает только значения true или false.

Пример с использованием enum:

{
"type": "boolean",
"enum": [true]
}

Эта схема требует, чтобы значение было true.

Пример с использованием const:

{
"type": "boolean",
"const": false
}

Эта схема требует, чтобы значение было false.

Когда использовать boolean Тип boolean полезен, когда нужно описать логические значения, такие как:

  • Флаги (true/false),
  • Переключатели (включено/выключено),
  • Условия (да/нет).

Тип array

Для типа array в схеме данных атрибута Памир существует множество ключевых слов (keywords), которые позволяют описывать структуру и ограничения для массивов.

  • items
    Определяет схему для элементов массива.

    • Если items — это объект, то все элементы массива должны соответствовать этой схеме.
    • Если items — это массив, то используется позиционная валидация (каждый элемент массива проверяется по соответствующей схеме).

    Пример (все элементы должны быть строками):

    {
    "type": "array",
    "items": {
    "type": "string"
    }
    }

    Пример (позиционная валидация):

    {
    "type": "array",
    "items": [
    { "type": "string" },
    { "type": "number" }
    ]
    }

    Первый элемент должен быть строкой, второй — числом.

  • minItems
    Определяет минимальное количество элементов в массиве.
    Пример:

    {
    "type": "array",
    "minItems": 2
    }

    Массив должен содержать не менее 2 элементов.

  • maxItems
    Определяет максимальное количество элементов в массиве.
    Пример:

    {
    "type": "array",
    "maxItems": 5
    }

    Массив должен содержать не более 5 элементов.

  • uniqueItems
    Указывает, что все элементы массива должны быть уникальными.
    Пример:

    {
    "type": "array",
    "uniqueItems": true
    }

    Все элементы массива должны быть уникальными.

  • additionalItems
    Определяет, разрешены ли дополнительные элементы в массиве, если используется позиционная валидация (items как массив).

    • Если additionalItems: false, то дополнительные элементы запрещены.
    • Если additionalItems: true или указана схема, то дополнительные элементы разрешены.

    Пример:

    {
    "type": "array",
    "items": [
    { "type": "string" },
    { "type": "number" }
    ],
    "additionalItems": false
    }

    Массив может содержать только два элемента: строку и число.

  • contains
    Указывает, что массив должен содержать хотя бы один элемент, соответствующий указанной схеме.
    Пример:

    {
    "type": "array",
    "contains": {
    "type": "number"
    }
    }

    Массив должен содержать хотя бы одно число.

Пример JSON Schema для типа array:

{
"type": "array",
"items": {
"type": "string",
"minLength": 3
},
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}

Эта схема требует, чтобы массив:

  • Содержал от 1 до 10 элементов,
  • Каждый элемент был строкой длиной не менее 3 символов,
  • Все элементы были уникальными.

Пример с contains:

{
"type": "array",
"items": {
"type": "number"
},
"contains": {
"type": "number",
"minimum": 10
}
}

Эта схема требует, чтобы массив содержал хотя бы одно число, которое больше или равно 10.

Тип object

Для типа array в схеме данных атрибута Памир существует множество ключевых слов (keywords), которые позволяют описывать структуру и ограничения для объектов. Вот основные из них:

  • properties
    Определяет свойства объекта и их схемы.
    Пример:

    {
    "type": "object",
    "properties": {
    "name": { "type": "string" },
    "age": { "type": "number" }
    }
    }

    Объект может содержать свойства name (строка) и age (число).

  • required
    Указывает список обязательных свойств объекта.
    Пример:

    {
    "type": "object",
    "properties": {
    "name": { "type": "string" },
    "age": { "type": "number" }
    },
    "required": ["name"]
    }

    Свойство name обязательно, а age — нет.

  • additionalProperties
    Определяет, разрешены ли дополнительные свойства, не указанные в properties.

    • Если additionalProperties: false, дополнительные свойства запрещены.
    • Если additionalProperties: true или указана схема, дополнительные свойства разрешены.

    Пример:

    {
    "type": "object",
    "properties": {
    "name": { "type": "string" }
    },
    "additionalProperties": false
    }

    Объект может содержать только свойство name.

  • patternProperties
    Определяет схемы для свойств, имена которых соответствуют регулярным выражениям.
    Пример:

    {
    "type": "object",
    "patternProperties": {
    "^S_": { "type": "string" },
    "^N_": { "type": "number" }
    }
    }

    Свойства, начинающиеся с S_, должны быть строками, а начинающиеся с N_ — числами.

  • minProperties
    Определяет минимальное количество свойств в объекте.
    Пример:

    {
    "type": "object",
    "minProperties": 2
    }

    Объект должен содержать не менее 2 свойств.

  • maxProperties
    Определяет максимальное количество свойств в объекте.
    Пример:

    {
    "type": "object",
    "maxProperties": 5
    }

    Объект должен содержать не более 5 свойств.

  • propertyNames
    Определяет схему для имен свойств объекта.
    Пример:

    {
    "type": "object",
    "propertyNames": {
    "pattern": "^[A-Za-z_]+$"
    }
    }

    Имена свойств должны состоять только из букв и символа _.

  • dependencies
    Указывает зависимости между свойствами.

    • Если зависимость — это массив, то при наличии одного свойства должны присутствовать и другие.
    • Если зависимость — это схема, то при наличии одного свойства объект должен соответствовать указанной схеме.

    Пример:

    {
    "type": "object",
    "properties": {
    "name": { "type": "string" },
    "age": { "type": "number" }
    },
    "dependencies": {
    "age": ["name"]
    }
    }

    Если есть свойство age, то должно быть и свойство name.

Пример JSON Schema для типа object

{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number", "minimum": 0 }
},
"required": ["name"],
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 3
}

Эта схема требует, чтобы объект:

  • Содержал обязательное свойство name (строка),
  • Мог содержать свойство age (число, не меньше 0),
  • Не содержал других свойств (additionalProperties: false),
  • Содержал от 1 до 3 свойств.

Пример с patternProperties:

{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^N_": { "type": "number" }
},
"additionalProperties": false
}

Эта схема требует, чтобы:

  • Свойства, начинающиеся с S_, были строками,
  • Свойства, начинающиеся с N_, были числами,
  • Другие свойства были запрещены.

Пример с dependencies:

{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number" },
"license": { "type": "boolean" }
},
"dependencies": {
"license": ["age"]
}
}

Эта схема требует, чтобы:

  • Если есть свойство license, то должно быть и свойство age.

Составные типы

Схема данных атрибута Памир составные типы позволяют комбинировать несколько схем или типов данных для создания более сложных и гибких правил валидации. Они используются, когда нужно описать данные, которые могут соответствовать одному из нескольких типов, или когда нужно применить несколько условий одновременно. Ключевые слова для работы с составными типами:

  • allOf Указывает, что данные должны соответствовать всем указанным схемам одновременно.
    Пример:
    {
    "allOf": [
    { "type": "string" },
    { "minLength": 5 }
    ]
    }

Данные должны быть строкой длиной не менее 5 символов.


  • anyOf Указывает, что данные должны соответствовать хотя бы одной из указанных схем.
    Пример:
    {
    "anyOf": [
    { "type": "string" },
    { "type": "number" }
    ]
    }

Данные могут быть либо строкой, либо числом.


  • oneOf Указывает, что данные должны соответствовать только одной из указанных схем (но не нескольким одновременно).
    Пример:
    {
    "oneOf": [
    { "type": "string" },
    { "type": "number" }
    ]
    }

Данные могут быть либо строкой, либо числом, но не одновременно и тем, и другим.


  • not Указывает, что данные не должны соответствовать указанной схеме.
    Пример:
    {
    "not": {
    "type": "string"
    }
    }

Данные не должны быть строкой.


  • if / then / else Позволяет задать условную логику валидации.
  • if: Условие, которое проверяется.
  • then: Схема, которая применяется, если условие истинно.
  • else: Схема, которая применяется, если условие ложно.

Пример:

{
"type": "object",
"properties": {
"isMember": { "type": "boolean" }
},
"if": {
"properties": {
"isMember": { "const": true }
}
},
"then": {
"required": ["memberId"]
},
"else": {
"required": ["guestId"]
}
}

Если isMember равно true, то обязательно должно быть свойство memberId. В противном случае обязательно должно быть свойство guestId.

Примеры использования составных типов

Пример 1: Комбинация allOf и anyOf

{
"allOf": [
{ "type": "object" },
{
"anyOf": [
{ "required": ["name"] },
{ "required": ["email"] }
]
}
]
}

Данные должны быть объектом и содержать либо свойство name, либо свойство email.


Пример 2: Использование oneOf

{
"oneOf": [
{ "type": "string", "maxLength": 10 },
{ "type": "number", "minimum": 0 }
]
}

Данные могут быть либо строкой длиной не более 10 символов, либо числом, не меньшим 0.


Пример 3: Использование not

{
"not": {
"type": "array"
}
}

Данные не должны быть массивом.


Пример 4: Условная валидация с if / then / else

{
"type": "object",
"properties": {
"age": { "type": "number" }
},
"if": {
"properties": {
"age": { "minimum": 18 }
}
},
"then": {
"required": ["license"]
},
"else": {
"required": ["parentConsent"]
}
}

Если возраст (age) больше или равен 18, то обязательно должно быть свойство license. В противном случае обязательно должно быть свойство parentConsent.


Когда использовать составные типы:

  • allOf: Когда данные должны соответствовать нескольким схемам одновременно.
  • anyOf: Когда данные могут соответствовать одной из нескольких схем.
  • oneOf: Когда данные должны соответствовать только одной из нескольких схем.
  • not: Когда данные не должны соответствовать определенной схеме.
  • if / then / else: Когда валидация зависит от значения других полей.

Пример схемы с использованием типов

{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"age": {
"type": "integer",
"minimum": 0
},
"email": {
"type": "string",
"format": "email"
},
"isStudent": {
"type": "boolean"
},
"hobbies": {
"type": "array",
"items": {
"type": "string"
}
},
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^\\d{5}$" }
},
"required": ["city", "zip"]
}
},
"required": ["name", "age"]
}

Валидные данные:

{
"name": "Alice",
"age": 25,
"email": "alice@example.com",
"isStudent": true,
"hobbies": ["reading", "swimming"],
"address": {
"city": "New York",
"zip": "10001"
}
}

Невалидные данные:

{
"name": "", // пустая строка (нарушает minLength)
"age": -5, // отрицательное число (нарушает minimum)
"email": "not-an-email", // не соответствует формату email
"address": {
"city": "New York" // отсутствует обязательное поле "zip"
}
}

Визуальное представление атрибута

Визуальное представление атрибута позволяет настраивать внешний вид и поведение формы, созданной на основе схемы данных атрибута. В то время как схема данных атрибута определяет структуру данных и правила валидации, визуальное представление определяет, как эти данные будут отображаться в пользовательском интерфейсе.

В визуальном представлении атрибута Памир существует несколько ключевых слов (keywords):

  • ui:widget Указывает, какой компонент использовать для отображения поля.
    Пример:
    {
    "ui:widget": "code_editor"
    }
    Для отрисовки содержимого будет использоваться редактор кода.

Шаблон схемы атрибута

Из всей совокупности типов и форматов выделяются наиболее используемые случаи. Они сгруппированы в шаблоны:

  • Строка
    • Строка (длина строки ограничена размером 8 КБ)
    • Текст
    • Пароль
    • IP адрес ipv4
    • Цвет
    • E-mail
  • Число
    • Целое число
    • Число с плавающей точкой
  • Дата и время
    • Дата
    • Дата и время
  • Логический
    • Логический
  • Список
    • Список строк
  • Json
    • Объект
    • Массив