Form Make

JSON-схема экспорта и импорта форм

Полная спецификация JSON-структуры форм платформы Form Make. Используйте этот документ для программного создания форм через функцию импорта.

При импорте поле id корневого объекта игнорируется и генерируется автоматически. Поля updatedAt и createdAt устанавливаются сервером.


⚠️ Важное примечание (Лимиты)

При генерации или анализе форм обратите внимание на следующие особенности архитектуры:

  1. Разделы (section) не являются вопросами: Элементы в массиве questions с типом "type": "section" служат исключительно для визуального разделения формы на шаги/страницы. Они не содержат полей для ответов респондентов, за них нельзя начислить баллы. Не считайте их вопросами при подсчете общего количества вопросов или при формировании тестов.
  2. Ограничения (Limits): При генерации формы строго соблюдайте следующие лимиты:
  • Максимальное количество вопросов в форме: 100
  • Максимальное количество разделов (секций) в форме: 100
  • Максимальное количество вариантов ответов в одном вопросе: 100
  • Максимальное количество критериев (строк в таблицах сопоставления) в одном вопросе: 100
  • Длина заголовка вопроса: не более 512 символов
  • Длина описания вопроса: не более 2048 символов
  • Длина заголовка раздела: не более 512 символов
  • Длина описания раздела: не более 2048 символов
  • Длина текста подсказки/комментария: не более 1024 символов
  • Длина текста варианта ответа/критерия: не более 512 символов

Корневой объект

ПолеТипОбязательноеОписание
titlestringДаНазвание формы
descriptionstring | nullНетОписание формы
settingsobjectДаОбъект настроек формы
questionsarrayДаМассив вопросов и разделов

Настройки формы (settings)

Объект settings содержит четыре блока конфигурации.

Основные (settings.main)

ПолеТипПо умолчаниюОписание
requiredQuestionsByDefaultbooleantrueНовые вопросы обязательны по умолчанию
disableCopybooleanfalseЗапретить копирование текста формы
showAnswersbooleantrueПоказывать ответы респонденту после прохождения
showCorrectAnswersbooleantrueПоказывать правильные ответы
isUserAuthnumber0Авторизация: 0 — анонимный доступ, 1 — требуется авторизация
acceptUntilnumber0Дедлайн приёма ответов (Unix timestamp, мс). 0 — без ограничений
attemptsAllowednumber1Лимит попыток: 0 — без ограничений (многократно), 1 — одна попытка

Оценивание (settings.mark)

ПолеТипОписание
typenumberРежим оценивания: 2 — включено
systemnumber | nullШкала оценивания: 5 — пятибалльная
strictScoringbooleanВключено ли строгое оценивание (без частичных баллов)
marksarrayМассив оценок с порогами

Каждый элемент массива marks:

ПолеТипОписание
markstringОценка (например "5", "4")
ballnumberМинимальный порог баллов в процентах (0–100)
namestringНазвание оценки (например "Отлично")

Пример:

json"mark": {
  "type": 2,
  "system": 5,
  "strictScoring": true,
  "marks": [
    { "mark": "5", "ball": 85, "name": "Отлично" },
    { "mark": "4", "ball": 70, "name": "Хорошо" },
    { "mark": "3", "ball": 50, "name": "Удовлетворительно" },
    { "mark": "2", "ball": 25, "name": "Неудовлетворительно" },
    { "mark": "1", "ball": 0, "name": "Очень плохо" }
  ]
}

Дополнительные (settings.other)

ПолеТипПо умолчаниюОписание
isViewValidQuestionbooleantrueПодсвечивать валидность вопросов при заполнении
isViewFinalResultbooleanfalseПоказывать финальный результат
enabledRealTimeAcceptUntillbooleanfalseВключить таймер обратного отсчёта
durationRealTimeAcceptUntillnumber60000Длительность таймера в миллисекундах

Кастомизация (settings.customization)

ПолеТипОписание
themestringЦветовая тема формы (например "lime", "blue", "violet", "rose")

Структура вопроса

Каждый элемент массива questions — это объект вопроса. Все типы вопросов разделяют общий набор полей.

Общие поля

ПолеТипОписание
idstringУникальный идентификатор (UUID v7)
typestringТип вопроса (см. раздел «Типы вопросов»)
titlestringТекст вопроса или заголовок
requiredbooleanОбязательный ли вопрос для заполнения
only_correctbooleanРежим проверки правильных ответов
settingsobjectНастройки вопроса
answersarrayВарианты ответов
criterionsarrayКритерии (для табличных/матричных вопросов и сопоставления)
correctIdsstring[]Массив ID правильных ответов

Настройки вопроса (question.settings)

ПолеТипОписание
ballsbooleanВключена ли балловая оценка за вопрос
balls_countnumberКоличество баллов за правильный ответ
orderstringСортировка вариантов: "not" — без сортировки, "word" — по алфавиту, "random" — случайный порядок

Дополнительные поля (необязательные)

ПолеТипОписание
descriptionstring | nullОписание/инструкция к вопросу
enabledDescriptionbooleanПоказывать ли описание
bannerstring | nullURL изображения-баннера вопроса
commentstring | nullКомментарий автора
helpobject | nullПодсказка для респондента

Объект help:

ПолеТипОписание
valuestringТекст подсказки
ballnumberШтраф в баллах за использование подсказки

Типы вопросов

Все доступные значения поля type:

ТипНазваниеКатегория
input_textВвод текстаТекст
input_nameИмяТекст
textТекст (без вопроса)Текст
phoneНомер телефонаТекст
emailЭлектронная почтаТекст
numberЧислоТекст
linkСсылкаТекст
optionОдин вариантВыбор из вариантов
optionsНесколько вариантовВыбор из вариантов
choice_gridОценка по шкалеВыбор из вариантов
multi_choice_gridОценка по шкале (Мн. выбор)Выбор из вариантов
comparisonСопоставлениеВыбор из вариантов
orderУказание порядкаВыбор из вариантов
filling_gapsЗаполнение пропусковВыбор из вариантов
fileЗагрузка файловДругое
sectionРаздел (этап)Другое

input_text — Ввод текста

Поле для свободного текстового ввода. Поддерживает проверку правильного ответа по точному совпадению.

  • answers — массив с одним элементом, содержащим эталонный ответ ({ id, label }). Пустой массив, если правильный ответ не задан.
  • correctIds — массив с id правильного ответа из answers.
  • settings.ballstrue для включения начисления баллов.
  • help — необязательная подсказка.
json{
  "id": "q1",
  "type": "input_text",
  "title": "Назовите столицу Франции",
  "answers": [
    { "id": "a1", "label": "Париж" }
  ],
  "correctIds": ["a1"],
  "criterions": [],
  "required": true,
  "only_correct": true,
  "settings": { "balls": true, "balls_count": 2, "order": "not" },
  "description": "Введите название города",
  "enabledDescription": true,
  "help": { "value": "Город на Сене", "ball": 1 }
}

text — Информационный блок

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

  • answers — всегда пустой массив.
  • correctIds — не используется.
  • settings.ballsfalse.
json{
  "id": "q2",
  "type": "text",
  "title": "Внимательно прочитайте условия перед следующим блоком вопросов",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": false, "order": "not", "balls_count": 1 }
}

phone — Номер телефона

Поле ввода с маской телефонного номера. Без проверки правильного ответа.

json{
  "id": "q3",
  "type": "phone",
  "title": "Укажите контактный номер телефона",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": {}
}

email — Электронная почта

Поле ввода с валидацией формата email. Без проверки правильного ответа.

json{
  "id": "q4",
  "type": "email",
  "title": "Введите ваш адрес электронной почты",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": {}
}

input_name — Имя

Поле для ввода имени респондента. В форме может присутствовать только один такой вопрос. Без проверки правильного ответа.

json{
  "id": "q4_name",
  "type": "input_name",
  "title": "Укажите ваше имя",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": {}
}

number — Число

Поле для ввода числового значения. Поддерживает проверку правильного ответа.

  • answers — массив с одним элементом, содержащим правильное число в виде строки.
  • correctIds — массив с id правильного ответа.
json{
  "id": "q5",
  "type": "number",
  "title": "Сколько будет 2 + 2?",
  "answers": [
    { "id": "a5", "label": "4" }
  ],
  "correctIds": ["a5"],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": true, "balls_count": 1, "order": "not" }
}

Поле ввода с валидацией формата URL. Без проверки правильного ответа.

json{
  "id": "q6",
  "type": "link",
  "title": "Укажите ссылку на ваш GitHub-репозиторий",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": {}
}

option — Один вариант ответа

Вопрос с выбором одного правильного варианта из нескольких.

  • answers — массив вариантов ответа ({ id, label }).
  • correctIds — массив с одним id правильного варианта.
  • settings.order — сортировка: "not", "word", "random".
json{
  "id": "q7",
  "type": "option",
  "title": "Какой HTTP-метод используется для получения данных?",
  "answers": [
    { "id": "a7-1", "label": "GET" },
    { "id": "a7-2", "label": "POST" },
    { "id": "a7-3", "label": "DELETE" },
    { "id": "a7-4", "label": "PATCH" }
  ],
  "correctIds": ["a7-1"],
  "criterions": [],
  "required": true,
  "only_correct": true,
  "settings": { "balls": true, "balls_count": 1, "order": "not" }
}

options — Несколько вариантов ответа

Вопрос с выбором нескольких правильных вариантов (чекбоксы).

  • answers — массив вариантов.
  • correctIds — массив id всех правильных вариантов.
json{
  "id": "q8",
  "type": "options",
  "title": "Выберите технологии, относящиеся к Frontend",
  "answers": [
    { "id": "a8-1", "label": "HTML5" },
    { "id": "a8-2", "label": "CSS3" },
    { "id": "a8-3", "label": "React" },
    { "id": "a8-4", "label": "PostgreSQL" },
    { "id": "a8-5", "label": "Docker" }
  ],
  "correctIds": ["a8-1", "a8-2", "a8-3"],
  "criterions": [],
  "required": true,
  "only_correct": true,
  "settings": { "balls": true, "balls_count": 1, "order": "random" }
}

choice_grid — Оценка по шкале

Матричный вопрос: для каждой строки (критерия) респондент выбирает один вариант из столбцов. Используется для шкальных оценок.

  • answers — столбцы (шкала значений).
  • criterions — строки (оцениваемые критерии), формат: { id, label }.
  • correctIds — обычно пустой (субъективная оценка).
json{
  "id": "q9",
  "type": "choice_grid",
  "title": "Оцените ваш уровень владения (от 1 до 5)",
  "answers": [
    { "id": "col-1", "label": "1" },
    { "id": "col-2", "label": "2" },
    { "id": "col-3", "label": "3" },
    { "id": "col-4", "label": "4" },
    { "id": "col-5", "label": "5" }
  ],
  "criterions": [
    { "id": "row-1", "label": "HTML/CSS" },
    { "id": "row-2", "label": "JavaScript" },
    { "id": "row-3", "label": "React" }
  ],
  "correctIds": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": false, "order": "not", "balls_count": 1 }
}

multichoicegrid — Оценка по шкале (Мн. выбор)

Матричный вопрос с множественным выбором: для каждой строки можно отметить несколько столбцов.

  • answers — столбцы таблицы.
  • criterions — строки таблицы.
  • correctIds — массив строк формата "criterionId:answerId", задающий правильные пары «строка:столбец».
json{
  "id": "q10",
  "type": "multi_choice_grid",
  "title": "Сопоставьте технологии с областями применения",
  "answers": [
    { "id": "col-1", "label": "React" },
    { "id": "col-2", "label": "Python" },
    { "id": "col-3", "label": "PostgreSQL" }
  ],
  "criterions": [
    { "id": "row-1", "label": "Frontend" },
    { "id": "row-2", "label": "Backend" },
    { "id": "row-3", "label": "Базы данных" }
  ],
  "correctIds": [
    "row-1:col-1",
    "row-2:col-2",
    "row-3:col-3"
  ],
  "required": true,
  "only_correct": false,
  "settings": { "balls": true, "balls_count": 1, "order": "not" }
}

comparison — Сопоставление

Задание на установление соответствия: каждому элементу левого столбца (answers) нужно сопоставить элемент правого столбца (criterions).

Критически важно: массивы answers и criterions связаны по позиции (индексу): answers[0] отображается в паре с criterions[0], answers[1] — с criterions[1] и т.д. Длина обоих массивов должна совпадать.

Как работает answerId

Поле answerId в каждом критерии указывает на id элемента из answers, который является правильной парой для этого критерия. Система проверки сравнивает answerId критерия с id ответа, стоящего на той же позиции. Если они совпадают — пара считается правильной.

Таким образом, answerId — это не просто ссылка, а ключевой механизм проверки. criterions[i].answerId должен быть равен answers[i].id, чтобы пара на позиции i была засчитана как правильная.

Правила

  • answers — элементы левого столбца ({ id, label }).
  • criterions — элементы правого столбца. Каждый критерий содержит поле answerId, указывающее на id правильного ответа из answers.
  • correctIds — всегда пустой массив, связь задаётся через answerId в criterions.
  • Количество элементов в answers и criterions должно совпадать.

Пример

Задача: «Сопоставьте HTTP-коды с их значениями». Правильные пары:

  • 200 ↔ OK
  • 404 ↔ Not Found
  • 500 ↔ Internal Server Error
json{
  "id": "q11",
  "type": "comparison",
  "title": "Сопоставьте HTTP-коды с их значениями",
  "answers": [
    { "id": "left-1", "label": "200" },
    { "id": "left-2", "label": "404" },
    { "id": "left-3", "label": "500" }
  ],
  "criterions": [
    { "id": "right-1", "label": "OK", "answerId": "left-1" },
    { "id": "right-2", "label": "Not Found", "answerId": "left-2" },
    { "id": "right-3", "label": "Internal Server Error", "answerId": "left-3" }
  ],
  "correctIds": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": true, "balls_count": 1, "order": "not" }
}

Обратите внимание: criterions[0].answerId = "left-1" совпадает с answers[0].id = "left-1" → пара «200 ↔ OK» на позиции 0 засчитана как правильная. То же для позиций 1 и 2.

Типичная ошибка: если вы хотите перемешать правый столбец (например, показать «Not Found» первым), не меняйте порядок criterions напрямую. Вместо этого переставьте и answers, и criterions синхронно, сохраняя соответствие по индексам.

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

json{
  "answers": [
    { "id": "left-2", "label": "404" },
    { "id": "left-3", "label": "500" },
    { "id": "left-1", "label": "200" }
  ],
  "criterions": [
    { "id": "right-2", "label": "Not Found", "answerId": "left-2" },
    { "id": "right-3", "label": "Internal Server Error", "answerId": "left-3" },
    { "id": "right-1", "label": "OK", "answerId": "left-1" }
  ]
}

Здесь criterions[0].answerId = "left-2" = answers[0].id ✅. Порядок изменён, но пары остались корректными.


order — Указание порядка

Респондент расставляет элементы в правильном порядке. Порядок элементов в массиве answers — это правильный порядок.

  • answers — элементы в правильном порядке. При отображении перемешиваются (если settings.order = "random").
  • correctIds — обычно пустой, правильный порядок определяется позицией в массиве.
json{
  "id": "q12",
  "type": "order",
  "title": "Расположите этапы разработки в правильном порядке",
  "answers": [
    { "id": "s1", "label": "Анализ требований" },
    { "id": "s2", "label": "Проектирование" },
    { "id": "s3", "label": "Разработка" },
    { "id": "s4", "label": "Тестирование" },
    { "id": "s5", "label": "Развёртывание" }
  ],
  "criterions": [],
  "correctIds": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": true, "balls_count": 1, "order": "random" }
}

filling_gaps — Заполнение пропусков

Составной вопрос: текст с вставленными полями ввода и выпадающими списками. Массив answers содержит фрагменты трёх типов:

Тип фрагментаОписание
textСтатический текст
inputПоле ввода с вариантами (options)
selectВыпадающий список с вариантами (options)
  • answers[].type — тип фрагмента: "text", "input" или "select".
  • answers[].label — текст для фрагментов типа "text".
  • answers[].options — массив вариантов для "input" и "select" ({ id, label }).
  • correctIds — массив id правильных вариантов из options полей input и select.
json{
  "id": "q13",
  "type": "filling_gaps",
  "title": "Заполните пропуски в определении",
  "answers": [
    { "id": "f1", "type": "text", "label": "HTML расшифровывается как " },
    {
      "id": "f2",
      "type": "select",
      "options": [
        { "id": "opt-1", "label": "HyperText Markup Language" },
        { "id": "opt-2", "label": "HighText Machine Language" },
        { "id": "opt-3", "label": "HyperTool Multi Language" }
      ]
    },
    { "id": "f3", "type": "text", "label": ". Файлы имеют расширение " },
    {
      "id": "f4",
      "type": "input",
      "options": [
        { "id": "opt-4", "label": ".html" }
      ]
    }
  ],
  "correctIds": ["opt-1", "opt-4"],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": true, "balls_count": 1 }
}

file — Загрузка файлов

Поле для загрузки файла респондентом. Без проверки правильного ответа.

json{
  "id": "q14",
  "type": "file",
  "title": "Загрузите скриншот выполненного задания",
  "answers": [],
  "correctIds": [],
  "criterions": [],
  "required": true,
  "only_correct": false,
  "settings": { "balls": false, "order": "not", "balls_count": 1 }
}

section — Раздел (этап)

Разделитель, который делит форму на логические этапы (страницы). Не является вопросом — используется для структурирования формы.

  • enabledTitle — отображать ли заголовок раздела.
  • enabledDescription — отображать ли описание раздела.
  • banner — URL баннера раздела.
  • settings.order — порядок вопросов внутри раздела: "not" — по порядку, "random" — случайный.

Важное примечание: Элемент с "type": "section" не является вопросом, а является разделителем страниц/этапов. Он располагается в массиве questions исключительно из-за линейной древовидной структуры схемы. Игнорируйте элементы section при подсчете общего количества вопросов в тесте или форме.

Первый элемент массива questions всегда является разделом — это корневой этап формы. Каждый последующий элемент section начинает новый этап.

json{
  "id": "sec-1",
  "type": "section",
  "title": "Теоретическая часть",
  "answers": [],
  "criterions": [],
  "required": true,
  "only_correct": true,
  "settings": { "order": "not" },
  "description": "Ответьте на вопросы по теории",
  "enabledTitle": true,
  "enabledDescription": true
}

Готовый пример для импорта

Полный пример JSON-формы, готовый для импорта через функцию «Импорт формы»:

json{
  "title": "Тестирование по основам веб-разработки",
  "description": "Демонстрационная форма с различными типами вопросов",
  "settings": {
    "main": {
      "requiredQuestionsByDefault": true,
      "disableCopy": false,
      "showAnswers": true,
      "showCorrectAnswers": true,
      "isUserAuth": 0,
      "acceptUntil": 0,
      "attemptsAllowed": 1
    },
    "mark": {
      "type": 2,
      "system": 5,
      "marks": [
        { "mark": "5", "ball": 85, "name": "Отлично" },
        { "mark": "4", "ball": 70, "name": "Хорошо" },
        { "mark": "3", "ball": 50, "name": "Удовлетворительно" },
        { "mark": "2", "ball": 0, "name": "Неудовлетворительно" }
      ]
    },
    "other": {
      "isViewValidQuestion": true,
      "isViewFinalResult": false,
      "enabledRealTimeAcceptUntill": false,
      "durationRealTimeAcceptUntill": 60000
    },
    "customization": {
      "theme": "lime"
    }
  },
  "questions": [
    {
      "id": "sec-1",
      "type": "section",
      "title": "Основы HTML и CSS",
      "answers": [],
      "criterions": [],
      "required": true,
      "only_correct": true,
      "settings": { "order": "not" },
      "description": "Вопросы по базовым технологиям фронтенда",
      "enabledTitle": true,
      "enabledDescription": true
    },
    {
      "id": "q-1",
      "type": "option",
      "title": "Какой тег используется для создания гиперссылки в HTML?",
      "answers": [
        { "id": "a1", "label": "<a>" },
        { "id": "a2", "label": "<link>" },
        { "id": "a3", "label": "<href>" },
        { "id": "a4", "label": "<url>" }
      ],
      "correctIds": ["a1"],
      "criterions": [],
      "required": true,
      "only_correct": true,
      "settings": { "balls": true, "balls_count": 1, "order": "not" }
    },
    {
      "id": "q-2",
      "type": "options",
      "title": "Выберите валидные CSS-свойства",
      "answers": [
        { "id": "b1", "label": "color" },
        { "id": "b2", "label": "font-size" },
        { "id": "b3", "label": "text-bold" },
        { "id": "b4", "label": "margin" },
        { "id": "b5", "label": "box-color" }
      ],
      "correctIds": ["b1", "b2", "b4"],
      "criterions": [],
      "required": true,
      "only_correct": true,
      "settings": { "balls": true, "balls_count": 2, "order": "random" }
    },
    {
      "id": "q-3",
      "type": "input_text",
      "title": "Какое CSS-свойство задаёт цвет текста?",
      "answers": [
        { "id": "c1", "label": "color" }
      ],
      "correctIds": ["c1"],
      "criterions": [],
      "required": true,
      "only_correct": true,
      "settings": { "balls": true, "balls_count": 1, "order": "not" },
      "help": { "value": "Подсказка: это английское слово", "ball": 1 }
    },
    {
      "id": "sec-2",
      "type": "section",
      "title": "Практическая часть",
      "answers": [],
      "criterions": [],
      "required": true,
      "only_correct": true,
      "settings": { "order": "not" },
      "enabledTitle": true,
      "enabledDescription": false
    },
    {
      "id": "q-4",
      "type": "comparison",
      "title": "Сопоставьте HTML-теги с их назначением",
      "answers": [
        { "id": "d1", "label": "<p>" },
        { "id": "d2", "label": "<h1>" },
        { "id": "d3", "label": "<img>" }
      ],
      "criterions": [
        { "id": "e1", "label": "Параграф", "answerId": "d1" },
        { "id": "e2", "label": "Заголовок", "answerId": "d2" },
        { "id": "e3", "label": "Изображение", "answerId": "d3" }
      ],
      "correctIds": [],
      "required": true,
      "only_correct": false,
      "settings": { "balls": true, "balls_count": 1, "order": "not" }
    },
    {
      "id": "q-5",
      "type": "order",
      "title": "Расположите теги в порядке вложенности HTML-документа",
      "answers": [
        { "id": "f1", "label": "<!DOCTYPE html>" },
        { "id": "f2", "label": "<html>" },
        { "id": "f3", "label": "<head>" },
        { "id": "f4", "label": "<body>" }
      ],
      "criterions": [],
      "correctIds": [],
      "required": true,
      "only_correct": false,
      "settings": { "balls": true, "balls_count": 1, "order": "random" }
    }
  ]
}