Введение

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

Использование API в PHP коде

Класс Api предоставляет удобные методы для работы с базой данных напрямую из PHP кода, без необходимости делать HTTP запросы.

Инициализация API

Создайте экземпляр класса Api для работы с базой данных:

<?php require_once __DIR__ . '/api/api.php'; $api = new Api(); // API автоматически загружает настройки из api.json // и подключает драйвер базы данных, указанный в конфигурации ?>

💡 Важно!

  • • Драйвер подключается автоматически на основе настройки driver в api.json
  • • Поддерживается динамическое подключение драйверов (mysql, postgresql и т.д.)
  • • Драйвер инициализируется при первом использовании (lazy loading)

CRUD методы

Класс Api предоставляет следующие методы для работы с данными:

📋 list() - Получить список записей

<?php $api = new Api(); // Простой список $users = $api->list([ '@table' => 'users', 'status' => 'active', '@limit' => 10 ]); // С фильтрацией и сортировкой $orders = $api->list([ '@table' => 'orders', 'status' => 'pending', '@order' => 'created_at:desc', '@page' => 1, '@size' => 20 ]); // С JOIN $ordersWithUsers = $api->list([ '@table' => 'orders', '@join' => ['left:users[orders.user_id=users.id]'], '@return' => 'orders.id,orders.total,users.name:customer_name', '@order' => 'orders.created_at:desc' ]); ?>

👁️ read() - Получить одну запись

<?php $api = new Api(); // По ID $user = $api->read([ '@table' => 'users', 'id' => 'user123' ]); // С дополнительными полями $user = $api->read([ '@table' => 'users', 'id' => 'user123', '@return' => 'id,name,email,profile.avatar,settings.theme' ]); // Если id не указан, используется из маршрута (если доступен) $api->route = ['item' => 'user123', 'table' => 'users']; $user = $api->read(); ?>

🔗 apiRequest() - Запрос по URL (внутренний вызов без HTTP)

Выполняет запрос по строке URL эндпоинта, без HTTP — удобно для вызова из того же приложения (шаблоны, тег <variable>, контроллеры). Поддерживаются list, read, delete. create/update/save не поддерживаются (нужно тело запроса).

Форматы URL: /api/list/{table}?... → list(); /api/count/{table}?... → count(); /api/read/{table}/{id} → read(); /api/delete/{table}/{id} → delete(). Возвращает массив или null.

<?php $api = new Api(); // Список по URL $roles = $api->apiRequest('/api/list/users?type=role&@size=100&@order=name:asc'); // Одна запись по URL $page = $api->apiRequest('/api/read/pages/123'); $users = $api->apiRequest('api/list/users?status=active'); // Удаление по URL $result = $api->apiRequest('/api/delete/users/123'); ?>

➕ create() - Создать запись

<?php $api = new Api(); // Создание с простыми полями $newUser = $api->create([ '@table' => 'users', '@set' => [ 'name' => 'Иван Иванов', 'email' => 'ivan@example.com', 'status' => 'active' ], '@return' => 'id,name,email,created_at' ]); // Создание с вложенными JSON полями $newUser = $api->create([ '@table' => 'users', '@set' => [ 'name' => 'Иван Иванов', 'email' => 'ivan@example.com', 'profile.avatar' => 'https://example.com/avatar.jpg', 'profile.bio' => 'Разработчик', 'settings.theme' => 'dark', 'settings.notifications.email' => true ], '@return' => 'id,name,email,profile,settings' ]); ?>

✏️ update() - Обновить запись

<?php $api = new Api(); // Обновление по ID $result = $api->update([ '@table' => 'users', 'id' => 'user123', '@set' => [ 'status' => 'inactive', 'last_login' => date('Y-m-d H:i:s') ], '@return' => 'id,name,status,last_login' ]); // Массовое обновление с условиями $result = $api->update([ '@table' => 'users', 'last_login(lt)' => '2024-01-01', 'status' => 'active', '@set' => [ 'status' => 'inactive', 'deactivated_at' => date('Y-m-d H:i:s') ] ]); // Обновление JSON полей $result = $api->update([ '@table' => 'users', 'id' => 'user123', '@set' => [ 'profile.avatar.url' => 'https://new-avatar.jpg', 'profile.bio' => 'Новая биография', 'settings.theme' => 'light' ] ]); ?>

🗑️ delete() - Удалить запись

<?php $api = new Api(); // Удаление по ID $result = $api->delete([ '@table' => 'users', 'id' => 'user123' ]); // Массовое удаление с условиями $result = $api->delete([ '@table' => 'users', 'status' => 'inactive', 'last_login(lt)' => '2020-01-01' ]); // Удаление с возвратом удаленных записей $result = $api->delete([ '@table' => 'users', 'id' => 'user123', '@return' => 'id,name,email' ]); ?>

💾 save() - Создать или обновить

<?php $api = new Api(); // Если запись с таким ID существует - обновит, иначе создаст $result = $api->save([ '@table' => 'users', '@set' => [ 'id' => 'user123', 'name' => 'Иван Иванов', 'email' => 'ivan@example.com', 'status' => 'active' ], '@return' => 'id,name,email,created_at,updated_at' ]); // Без ID - всегда создаст новую запись $result = $api->save([ '@table' => 'users', '@set' => [ 'name' => 'Новый пользователь', 'email' => 'new@example.com' ] ]); ?>

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

Логические операции (OR и AND)

Синтаксис GET/POST, таблицы и сценарии — в разделе «Логические операции». Ниже — примеры для PHP API.

🔀 Использование @or (ИЛИ)

Оператор @or позволяет найти записи, которые соответствуют хотя бы одному из условий.

<?php $api = new Api(); // Найти пользователей со статусом "active" ИЛИ ролью "admin" $users = $api->list([ '@table' => 'users', '@or' => [ ['status' => 'active'], ['role' => 'admin'] ] ]); // Более сложный пример: активные пользователи ИЛИ администраторы ИЛИ модераторы $users = $api->list([ '@table' => 'users', '@or' => [ ['status' => 'active'], ['role' => 'admin'], ['role' => 'moderator'] ], '@order' => 'created_at:desc' ]); // Комбинация с другими условиями $users = $api->list([ '@table' => 'users', 'department' => 'IT', // Всегда должно быть выполнено '@or' => [ ['status' => 'active'], ['role' => 'admin'] ] ]); ?>

🔗 Использование @and (И)

Оператор @and позволяет явно указать, что все условия должны быть выполнены одновременно.

<?php $api = new Api(); // Найти пользователей со статусом "active" И возрастом больше 18 $users = $api->list([ '@table' => 'users', '@and' => [ ['status' => 'active'], ['age(gt)' => 18] ] ]); // Несколько условий с разными операторами $users = $api->list([ '@table' => 'users', '@and' => [ ['status' => 'active'], ['age(gte)' => 18], ['age(lte)' => 65], ['city(in)' => ['Moscow', 'SPB']] ] ]); ?>

Эквивалентный компактный формат: '@and' => ['date(gt)' => '...', 'date(lt)' => '...'] — то же самое, что канонический [['date' => ['gt' => '...']], ...].

🔀🔗 Комбинирование @or и @and

Вы можете создавать сложные вложенные структуры, комбинируя @or и @and.

<?php $api = new Api(); // Найти пользователей, которые: // (статус = "active" ИЛИ роль = "admin") И отдел = "IT" $users = $api->list([ '@table' => 'users', '@and' => [ [ '@or' => [ ['status' => 'active'], ['role' => 'admin'] ] ], ['department' => 'IT'] ] ]); // Более сложный пример: // (статус = "active" ИЛИ роль = "admin") // И // (возраст >= 18 И возраст <= 65) $users = $api->list([ '@table' => 'users', '@and' => [ [ '@or' => [ ['status' => 'active'], ['role' => 'admin'] ] ], [ '@and' => [ ['age(gte)' => 18], ['age(lte)' => 65] ] ] ] ]); // Использование в update() с условиями $result = $api->update([ '@table' => 'users', '@and' => [ [ '@or' => [ ['status' => 'active'], ['status' => 'pending'] ] ], ['last_login(lt)' => '2024-01-01'] ], '@set' => [ 'status' => 'inactive', 'deactivated_at' => date('Y-m-d H:i:s') ] ]); // Использование в delete() с условиями $result = $api->delete([ '@table' => 'users', '@or' => [ ['status' => 'deleted'], ['last_login(lt)' => '2020-01-01'] ] ]); ?>

💡 Важные моменты:

  • • По умолчанию все условия объединяются через AND, если не указан @or
  • @and полезен для явного указания логики, особенно при комбинации с @or
  • • Можно создавать многоуровневые вложенные структуры
  • • Логические операторы работают во всех CRUD методах: list(), read(), update(), delete()

Работа с драйверами и подключениями

В настройках можно задать несколько именованных подключений. У каждого указывается type (mysql, json, mongodb) и параметры. Поле driver в корне — имя подключения по умолчанию.

Пример api.json (несколько подключений):

{ "driver": "mysql", "drivers": { "mysql": { "type": "mysql", "host": "localhost", "port": 3306, "database": "mydb", "username": "user", "password": "pass" }, "json": { "type": "json", "database_path": "/path/to/json", "allowed_tables": [] } } }

💡 Как это работает:

  • • Подключение по умолчанию задаётся в "driver"
  • • В запросе можно указать @driver или @db для выбора подключения
  • • Файл драйвера загружается по полю type подключения: drivers/{type}.php
  • • Экземпляр драйвера кэшируется по имени подключения

Практические примеры

Пример 1: Получение данных с фильтрацией

<?php $api = new Api(); // Получить активных пользователей за последний месяц $activeUsers = $api->list([ '@table' => 'users', 'status' => 'active', 'created_at(gte)' => date('Y-m-01'), '@order' => 'created_at:desc', '@page' => 1, '@size' => 50 ]); foreach ($activeUsers as $user) { echo $user['name'] . " - " . $user['email'] . "\n"; } ?>

Пример 2: Создание записи с валидацией

<?php $api = new Api(); // Проверить, существует ли пользователь $existingUser = $api->read([ '@table' => 'users', 'email' => 'ivan@example.com' ]); if (!$existingUser) { // Создать нового пользователя $newUser = $api->create([ '@table' => 'users', '@set' => [ 'name' => 'Иван Иванов', 'email' => 'ivan@example.com', 'status' => 'active' ] ]); echo "Пользователь создан: " . $newUser['id']; } else { echo "Пользователь уже существует"; } ?>

Пример 3: Использование save() для upsert

<?php $api = new Api(); // Автоматически создаст или обновит запись $result = $api->save([ '@table' => 'users', '@set' => [ 'id' => 'user123', 'name' => 'Иван Иванов', 'email' => 'ivan@example.com', 'last_seen' => date('Y-m-d H:i:s') ] ]); // Не нужно проверять существование - save() сделает это сам ?>

Пример 4: Работа с JOIN

<?php $api = new Api(); // Получить заказы с информацией о пользователях $orders = $api->list([ '@table' => 'orders', '@join' => ['left:users[orders.user_id=users.id]'], '@return' => 'orders.id,orders.total,orders.created_at,users.name:customer_name,users.email:customer_email', 'orders.status' => 'completed', '@order' => 'orders.created_at:desc', '@page' => 1, '@size' => 20 ]); foreach ($orders as $order) { echo "Заказ #{$order['id']} от {$order['customer_name']} на сумму {$order['total']}\n"; } ?>

Пример 5: Массовые операции

<?php $api = new Api(); // Обновить статус всех неактивных пользователей $result = $api->update([ '@table' => 'users', 'status' => 'active', 'last_login(lt)' => '2024-01-01', '@set' => [ 'status' => 'inactive', 'deactivated_at' => date('Y-m-d H:i:s') ] ]); echo "Обновлено записей: " . ($result['affected'] ?? 0); // Удалить старые записи $result = $api->delete([ '@table' => 'logs', 'created_at(lt)' => date('Y-m-d', strtotime('-1 year')) ]); echo "Удалено записей: " . ($result['affected'] ?? 0); ?>

Преимущества использования PHP методов

  • Нет HTTP overhead - прямые вызовы методов без сетевых запросов
  • Типобезопасность - IDE подсказки и проверка типов
  • Производительность - быстрее чем HTTP запросы
  • Удобство отладки - можно использовать отладчик PHP
  • Единый код - один и тот же API для HTTP и PHP вызовов
  • Автоматический парсинг - запросы парсятся автоматически
  • Несколько подключений — в запросах можно указывать @driver или @db для выбора подключения

Подключения и алиасы таблиц

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

Несколько подключений (Database)

В настройках (раздел Database) можно добавить несколько подключений с произвольными именами (например mysql, json, mysql_db2). У каждого подключения задаётся тип (MySQL, JSON, MongoDB) и параметры. Одно из подключений выбирается как Default connection — оно используется, если в запросе не указан @driver/@db и таблица не найдена в алиасах.

Параметры @driver и @db

Чтобы явно выбрать подключение в запросе, укажите его имя:

  • @driver=имя_подключения — выбор подключения
  • @db=имя_подключения — то же самое (синоним)
GET /api/list/users?@driver=json GET /api/list/pages?@db=mysql_db2

Если указан @driver или @db, алиасы таблиц не применяются.

Алиасы таблиц (Aliases)

В разделе Aliases настраивается соответствие: имя алиасаподключение + таблица. При запросе с @table=алиас API обращается к указанному подключению и таблице. Если алиаса нет и не задан @driver/@db, используется подключение по умолчанию и имя таблицы как есть.

Пример:

Алиас jUsers → подключение json, таблица users. Запрос GET /api/list/jUsers вернёт данные из таблицы users в JSON-подключении.

Быстрый старт

Пошаговое руководство по подключению API к вашему проекту.

Шаг 1: Клонирование репозитория

Клонируйте репозиторий API на ваш сервер:

git clone https://gitflic.ru/project/digiport/api.git

Или добавьте как подмодуль в существующий проект:

git submodule add https://gitflic.ru/project/digiport/api.git api

Структура файлов после клонирования:

project/ ├── api/ │ ├── api.php # Точка входа │ ├── api_parser.php # Парсер запросов │ ├── drivers/ │ │ └── mysql.php # MySQL драйвер │ ├── api_router.php # Роутер │ ├── api_settings.php # Веб-интерфейс настроек │ ├── api_help.php # Эта документация │ ├── api.ini # Маршруты │ └── api.json # Настройки пакета api (fallback) ├── database/ │ └── api.json # Настройки проекта (создастся автоматически) └── index.php # Ваше приложение

⚠️ Требования:

  • Убедитесь, что веб-сервер имеет доступ к файлам API
  • Проверьте права на запись для файла database/api.json (хранит настройки проекта)
  • PHP версии 7.4 или выше

Шаг 2: Подключение в вашем проекте

Добавьте следующий код в самое начало вашего основного файла (например, index.php):

require_once __DIR__ . '/api/api.php'; $api = new Api(); $api->run(); // Далее сод вашего приложения

💡 Важно!

  • • Код должен быть добавлен в самом начале файла, до любого вывода HTML
  • • API обрабатывает только запросы к /api/*
  • • Если запрос не к API, выполнение продолжается дальше в вашем коде
  • • Не нужен закрывающий тег ?> в конце файла

Шаг 3: Настройка через веб-интерфейс

  1. Откройте в браузере: http://ваш-сайт.com/api/settings
  2. При первом входе используйте дефолтный пароль: password

    ⚠️ Важно!

    После первого входа обязательно смените пароль на безопасный в разделе "Tokens" → "Web Interface Password".

  3. В разделе Database (Connections) добавьте одно или несколько подключений (имя, тип: MySQL/JSON/MongoDB, параметры). Выберите Default connection. При необходимости в разделе Aliases настройте алиасы таблиц (имя алиаса → подключение + таблица).
  4. Нажмите кнопку "Save Settings" для сохранения настроек

Шаг 4: Первый запрос

Проверьте работу API, выполнив простой запрос:

GET http://ваш-сайт.com/api/list/users?@limit=10

Или используйте cURL:

curl http://ваш-сайт.com/api/list/users?@limit=10

🔒 Если API защищен токеном:

curl -H "Authorization: Bearer YOUR_TOKEN" \ http://ваш-сайт.com/api/list/users?@limit=10

Шаг 5: Обновление кода

Для обновления API до последней версии выполните:

cd api git pull origin master

Если используете подмодуль:

git submodule update --remote api

💡 Рекомендация:

Перед обновлением сделайте резервную копию файла api.json с настройками, так как обновление может изменить структуру конфигурации.

✅ Готово!

Теперь ваш API полностью настроен. Настройте подключения и алиасы и токены в панели настроек.

Аутентификация

Токен передаётся только в HTTP-заголовке Authorization: Bearer. Параметр @token в URL или JSON не принимается.

Bearer Token

Authorization: Bearer YOUR_SECRET_TOKEN
curl -H "Authorization: Bearer YOUR_SECRET_TOKEN" \ https://ваш-сайт.com/api/list/users

JavaScript (fetch):

fetch('/api/list/users?@limit=10', { headers: { Authorization: 'Bearer YOUR_SECRET_TOKEN' } });

Управление API

Раздел Security позволяет настроить пароль веб-интерфейса, HTTPS и токены доступа с правами по умолчанию и переопределениями по таблицам.

Создание токена через веб-интерфейс

  1. Откройте панель управления:
    http://ваш-сайт.com/api/settings
  2. Перейдите в раздел Security (Tokens) в боковом меню
  3. Включите защиту API (переключатель "Protect API access with tokens")

    Если защита отключена, API доступен без токена

  4. Нажмите "+ Add Token" для создания нового токена
  5. Заполните параметры токена:
    • Token name — имя для идентификации (например, "Mobile App", "Frontend")
    • Token — сам токен (кнопка 🔄 для автогенерации)
    • Default — общие права по умолчанию для всех таблиц: C Create, R Read, U Update, D Delete, S Save, L List
    • Table-specific permissions — при необходимости задайте переопределения прав для отдельных таблиц (например, для таблицы users только L). Если переопределения нет, используются права по умолчанию
  6. Нажмите "Save Settings" для сохранения изменений

💡 Пример:

Имя: "Mobile App"

Default: R, L (чтение и список)

Переопределение: для таблицы users — только L

Получение токена программно

Вы можете получить токен из настроек API в вашем PHP коде:

<?php require_once __DIR__ . '/api/api.php'; $api = new Api(); // Получить токен по имени $token = $api->getToken('Mobile App Token'); if ($token) { echo "Token: " . $token['value'] . "\n"; echo "Access: " . implode(', ', $token['access']) . "\n"; } else { echo "Token not found\n"; } ?>

Результат:

Token: abc123xyz456def789... Access: r, l

Использование токена в запросах

Только заголовок Authorization: Bearer:

curl -H "Authorization: Bearer YOUR_SECRET_TOKEN" \ https://ваш-сайт.com/api/list/users

Ограничение доступа к таблицам

Токены можно ограничить конкретными таблицами для повышения безопасности:

✅ Токен с доступом к users

GET /api/list/users → ✅ Разрешено

❌ Токен без доступа к orders

GET /api/list/orders → ❌ 403 Access denied

⚠️ Важно:

Если список таблиц пуст, токен имеет доступ ко ВСЕМ таблицам (с учетом разрешений C/R/U/D/S/L).

Примеры разрешений токенов

📱 Мобильное приложение

Разрешения: R, L (только чтение)

Таблицы: users, products, categories

🖥️ Панель администратора

Разрешения: C, R, U, D, S, L (полный доступ)

Таблицы: все (список пуст)

📊 Сервис аналитики

Разрешения: L (только списки)

Таблицы: orders, analytics

⚙️ Внешняя интеграция

Разрешения: C, U, S (создание и обновление)

Таблицы: webhooks, sync_log

🔐 Безопасность токенов

  • Храните токены в безопасном месте (переменные окружения, защищенные конфиги)
  • Параметр @token в URL и JSON не принимается — только заголовок Authorization: Bearer
  • Регулярно меняйте токены для критичных систем
  • Используйте разные токены для разных приложений
  • Настраивайте минимальные необходимые разрешения (принцип наименьших привилегий)

Действия (CRUD операции)

API поддерживает полный набор CRUD операций для работы с данными.

LIST - Получение списка

Получить список записей с фильтрацией, сортировкой и пагинацией.

GET /api/list/users?status=active&@page=1&@size=10

COUNT - Подсчёт записей

Подсчитать количество записей по тем же фильтрам, что у list, без загрузки списка. Право токена: l (как у list).

GET /api/count/classes?private=false&@or=(status=opened,status=closed)

Ответ: {"count": 182}

Уникальные значения поля: @distinct=email. Группировка: @group + агрегаты в @return (@supress включается автоматически).

GET /api/count/orders?@group=status&@return=status,@count(id):total

@query — экспорт запроса в PHP

Модификатор отладки: не выполняет запрос, возвращает только PHP-код в <pre> (HTML).

GET /api/count/classes?private=false&@or=(status=opened,status=closed)&@query=1

Из PHP $api->count([..., '@query' => 1]) — строка с тем же кодом. Работает с list, count, read, create, update, delete, save.

READ - Чтение одной записи

Получить одну запись по ID.

GET /api/read/users/user123

CREATE - Создание записи

Создать новую запись. Данные передаются через параметр @set или в теле POST запроса.

Способ 1: POST запрос с JSON телом

POST /api/create/users Content-Type: application/json { "@set": { "name": "Иван Иванов", "email": "ivan@example.com", "role": "user" }, "@return": "id,name,email,created_at" }

Способ 2: GET запрос с параметром @set

Для быстрого создания можно использовать GET запрос:

GET /api/create/users?@set=name=Иван%20Иванов&email=ivan@example.com&role=user&@return=id,name,email,created_at

Способ 3: GET с @set в квадратных скобках

Более читаемый вариант с использованием квадратных скобок:

GET /api/create/users?@set=[name=John%20Doe&email=john@example.com&role=admin]&@return=id,name,email

Создание с вложенными JSON полями через GET

GET /api/create/users?@set=name=John&email=john@test.com&profile.avatar=https://example.com/pic.jpg&profile.bio=Developer&settings.theme=dark&@return=id,name,profile,settings

То же самое с использованием квадратных скобок:

GET /api/create/users?@set=[name=John&email=john@test.com&profile.avatar=https://example.com/pic.jpg&profile.bio=Developer&settings.theme=dark]&@return=id,name,profile,settings

💡 Параметр @return указывает, какие поля вернуть после создания.

UPDATE - Обновление записи

Обновить существующую запись. Можно обновлять по ID или по условию.

Способ 1: POST запрос с JSON телом

POST /api/update/users/user123 { "@set": { "status": "inactive", "updated_at": "2025-11-11" }, "@return": "id,name,status" }

Способ 2: GET запрос с множественными @set

Для простых обновлений можно использовать GET запрос:

GET /api/update/users/user123?@set=status=inactive&@set=last_login=2025-11-11&@return=id,name,status

Способ 3: GET запрос с объединенным @set

Можно передать несколько полей в одном параметре @set, разделяя их через &:

GET /api/update/users/user123?@set=status=inactive&updated_at=2025-11-11&@return=id,name,status

Способ 4: GET запрос с @set в квадратных скобках (рекомендуется)

Квадратные скобки улучшают читаемость и чётко отделяют параметры @set от других:

GET /api/update/users/user123?@set=[status=inactive&updated_at=2025-11-11]&@return=id,name,status

Пример с токенами (ваш случай):

GET /api/update/users/user123?@set=[firebaseToken=abc123&mobileFirebaseToken=xyz789]&@return=id,firebaseToken,mobileFirebaseToken

Обновление JSON полей через GET

Используйте dot notation для вложенных полей:

GET /api/update/users/user123?@set=profile.avatar.url=https://new-avatar.jpg&profile.bio=Новая%20биография&@return=id,profile

DELETE - Удаление записи

Удалить запись по ID или по условию.

DELETE /api/delete/users/user123

Для массового удаления используйте POST с условиями фильтрации.

SAVE - Создание или обновление

Автоматически создает запись, если ID не существует, или обновляет существующую.

POST /api/save/users { "@set": { "id": "user123", "name": "Обновленное имя" } }

Сохранение вложенного JSON по URL

Сегмент {field} задаёт срез записи: поля из тела получают префикс {field}. Вложенный объект заменяется целиком.

POST /api/save/settings/modules/courses { "courses": [{"id": 1, "name": "Курс A"}], "expert": true, "time": 60 }

В формах engine: <data table="settings" item="modules" field="courses"> и action="/api/save/settings/modules/courses".

Условия

Вы можете фильтровать данные, указывая условия для отдельных полей. Условия можно передавать как в GET-запросах (через URL параметры), так и в POST-запросах (через JSON тело). Общий синтаксис: `field(operator)=value`. Если оператор не указан, по умолчанию используется `eq` (равно).

GET-запросы (URL параметры)

Условия передаются через URL параметры. Удобно для простых запросов и тестирования в браузере.

GET /api/users?status=active&age(gt)=18&name(like)=%john%

POST-запросы (JSON тело)

Условия передаются в JSON теле запроса. Позволяет передавать сложные структуры данных.

{
  "status": "active",
  "age(gt)": 18,
  "name(like)": "%john%"
}

Доступные операторы

Оператор Описание GET пример POST пример
`eq` (или нет) Равно status=active "status": "active"
`ne` Не равно status(ne)=archived "status(ne)": "archived"
`gt` Больше amount(gt)=100 "amount(gt)": 100
`lt` Меньше price(lt)=50 "price(lt)": 50
`gte` Больше или равно date(gte)=2025-01-01 "date(gte)": "2025-01-01"
`lte` Меньше или равно date(lte)=2025-12-31 "date(lte)": "2025-12-31"
`in` Входит в список role(in)=[admin,moderator] "role(in)": ["admin", "moderator"]
`not_in` Не входит в список category(not_in)=[spam,deleted] "category(not_in)": ["spam", "deleted"]
`contains` / `has` Поле (массив/JSON) содержит значение tags(contains)=important или tags(has)=important "tags(contains)": "important" или "tags(has)": "important"
`not_contains` / `not_has` Поле не содержит значение tags(not_contains)=spam "tags(not_contains)": "spam"
`between` Между диапазоном date(between)=[2025-07-01,2025-07-08] "date(between)": ["2025-07-01", "2025-07-08"]
`like` Похож (сопоставление по шаблону) name(like)=%book% "name(like)": "%book%"
`is_null` Равен NULL last_login(is_null)=true "last_login(is_null)": true
`not_null` Не равен NULL description(not_null)=true "description(not_null)": true
`empty` Пустое значение (NULL, пустая строка, пустой массив) email(empty)=true "email(empty)": true
`not_empty` Не пустое значение avatar(not_empty)=true "avatar(not_empty)": true
`not_between` Не между диапазоном date(not_between)=[2025-01-01,2025-06-30] "date(not_between)": ["2025-01-01", "2025-06-30"]
`not_like` Не похож (исключение по шаблону) name(not_like)=%test% "name(not_like)": "%test%"

Инверсия предикатов через =false

Булевые операторы (empty, not_empty, is_null, not_null): =false инвертирует оператор и трактуется как true.

GET /api/list/members?image(empty)=false GET /api/list/members?image=(empty)=false

Операторы со значением: синтаксис field(op=value)=false — значение сохраняется, оператор инвертируется (likenot_like, innot_in, containsnot_contains, betweennot_between).

GET /api/list/users?name(like=%ivan%)=false GET /api/list/members?@or=(teacher=true,admin=true)&active=true

Булевы JSON-поля в @or нормализуются в строки "true"/"false" для корректного сравнения в MySQL.

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

GET-запрос с несколькими условиями

Находит активных пользователей от 18 до 65 лет из Москвы или СПб, чьё имя содержит "john".

GET /api/users?status=active&age(gte)=18&age(lte)=65&city(in)=[Moscow,SPB]&name(like)=%john%

POST-запрос с несколькими условиями

Тот же запрос, но через POST с JSON телом.

{
  "status": "active",
  "age(gte)": 18,
  "age(lte)": 65,
  "city(in)": ["Moscow", "SPB"],
  "name(like)": "%john%"
}

Логические операции

Операторы @and и @or объединяют условия фильтрации. Работают в list, count, read, update, delete и при явном @where в save.

AND по умолчанию

Все параметры на верхнем уровне URL или JSON связаны через AND. Каждое условие должно выполняться одновременно.

GET /api/list/users?status=active&department=IT&age(gte)=18

status = active И department = IT И age ≥ 18

Когда что использовать

Задача Решение
A и B и CA=v1&B=v2&C=v3
A или B или C@or=(A,B,C)
(A или B) и C@or=(A,B)&C=v
Глубокая вложенностьPOST JSON или PHP-массив

GET-запросы

Внутри @or=(...) или @and=(...) условия разделяются запятой или &. Значения в [...] не разбиваются.

Простое ИЛИ

GET /api/list/users?@or=(status=active,role=admin)

ИЛИ + обязательное условие (частый паттерн)

GET /api/list/users?@or=(status=active,role=admin)&department=IT

→ (status = active OR role = admin) AND department = IT

Разные поля и операторы

GET /api/list/members?active=true&@or=(teacher=true,admin=true) GET /api/list/users?@or=(age(lt)=18,age(gt)=65)&status=active GET /api/count/classes?private=false&@or=(status=opened,status=closed)

Предикаты empty и инверсия =false

GET /api/list/users?@or=(profile.avatar(empty)=true,profile.bio(empty)=true)&status=active GET /api/list/members?image(empty)=false GET /api/list/users?@or=(name(like=%test%)=false,city(ne)=archive)

in vs @or

Для одного поля с несколькими значениями короче in:

GET /api/list/orders?status(in)=[pending,processing] # эквивалент: GET /api/list/orders?@or=(status=pending,status=processing)

@or нужен, когда условия на разных полях или с разными операторами.

POST-запросы (JSON)

Для вложенных структур и длинных условий. Поддерживаются канонический массив и компактный объект — оба нормализуются парсером.

Канонический формат

POST /api/list/users { "@and": [ { "@or": [ {"status": "active"}, {"role": "admin"} ] }, {"department": "IT"} ] }

Компактный формат

{ "@and": { "@or": { "status": "active", "role": "admin" }, "department": "IT" } }

Булевы JSON-поля

POST /api/list/members { "active": true, "@or": [ {"teacher": true}, {"admin": true} ] }

Сводка: GET ↔ POST

Смысл GET POST
A или B@or=(A,B)"@or": [{"f1":"v1"}, {"f2":"v2"}]
(A или B) и C@or=(A,B)&C=v"@or":[...], "C":"v"
A и B и CA=v1&B=v2"A":"v1", "B":"v2"

Типичные сценарии

Массовый update по условию OR

POST /api/update/orders { "@or": [ {"status": "cancelled"}, {"due_date(lt)": "2025-01-01"} ], "@set": {"status": "archived"} }

Массовый delete

POST /api/delete/sessions { "@or": [ {"expires_at(lt)": "2025-01-01"}, {"revoked": true} ] }

Dot notation внутри логики

GET /api/list/users?@or=(settings.theme=dark,settings.theme=auto)&profile.verified=true

PHP API

Те же структуры в $api->list(), count(), update(), delete(). Раздел «Использование в PHP» содержит расширенные примеры вложенности.

$api->list([ '@table' => 'users', 'department' => 'IT', '@or' => [ ['status' => 'active'], ['role' => 'admin'], ], ]);

Важные моменты

  • Параметры верхнего уровня — всегда AND, если не сгруппированы в @or.
  • Внутри (...) разделители — запятая или &; между параметрами URL — только &.
  • Булевы JSON-поля в @or нормализуются в строки "true"/"false" для MySQL.
  • Сложная многоуровневая вложенность — POST или PHP, не длинный GET.
  • count использует те же @or/@and, что и list.
  • Инверсия предикатов =false работает внутри @or/@and — см. раздел «Условия».

Объединения (JOIN)

Параметр `@join` позволяет объединять данные из нескольких связанных таблиц в одном запросе, значительно упрощая работу с реляционными данными.

Базовый синтаксис

Параметр `@join` принимает массив строк, где каждая строка описывает одно присоединение:

Формат:

[тип]:[таблица][[условие_связи]]

Тип JOIN

inner, left, right, full

Таблица

Имя присоединяемой таблицы

Условие

Поля для связи таблиц

Простой пример:

@join=["left:users[orders.user_id=users.id]"]

Присоединяет таблицу users к таблице orders по полю user_id

Типы JOIN

🔹 INNER JOIN (inner)

Возвращает только записи, для которых найдено совпадение в обеих таблицах.

@join=["inner:users[orders.user_id=users.id]"]

Результат: Только заказы, у которых есть пользователь

🔹 LEFT JOIN (left)

Возвращает все записи из левой таблицы и совпадающие из правой. Если совпадений нет, поля правой таблицы будут NULL.

@join=["left:users[orders.user_id=users.id]"]

Результат: Все заказы, даже если пользователь не найден (поля user будут NULL)

🔹 RIGHT JOIN (right)

Возвращает все записи из правой таблицы и совпадающие из левой.

@join=["right:users[orders.user_id=users.id]"]

Результат: Все пользователи, даже без заказов

🔹 FULL JOIN (full)

Возвращает все записи из обеих таблиц, даже без совпадений.

@join=["full:users[orders.user_id=users.id]"]

Результат: Все заказы и все пользователи

💡 Рекомендация:

Используйте LEFT JOIN в 90% случаев - это самый распространенный и безопасный тип объединения.

Множественные JOIN

Можно объединить несколько таблиц в одном запросе:

GET запрос:

GET /api/list/orders?@join=["left:users[orders.user_id=users.id]","inner:products[orders.product_id=products.id]"]&@return=orders.id,users.name:customer_name,products.name:product_name

POST запрос (рекомендуется для сложных JOIN):

POST /api/list/orders Content-Type: application/json { "@join": [ "left:users[orders.user_id=users.id]", "inner:products[orders.product_id=products.id]", "left:categories[products.category_id=categories.id]" ], "@return": "orders.id,users.name:customer,products.name:product,categories.name:category,orders.total" }

Результат: Заказы с данными пользователя, продукта и категории в одном запросе

Практические примеры

📱 Пример 1: Заказы с пользователями

Получить все заказы со статусом "pending" и информацией о пользователях:

GET /api/list/orders?status=pending&@join=["left:users[orders.user_id=users.id]"]&@return=orders.*,users.name,users.email&@order=orders.created_at:desc

🛒 Пример 2: Продукты с категориями и производителями

Каталог продуктов с полной информацией:

POST /api/list/products { "@join": [ "left:categories[products.category_id=categories.id]", "left:manufacturers[products.manufacturer_id=manufacturers.id]" ], "@return": "products.id,products.name,products.price,categories.name:category,manufacturers.name:brand", "products.status": "active", "@order": "products.price:asc", "@page": 1, "@size": 20 }

👥 Пример 3: Пользователи с количеством заказов

Список пользователей с статистикой их заказов:

POST /api/list/users { "@join": [ "left:orders[users.id=orders.user_id]" ], "@return": "users.id,users.name,users.email,@count(orders.id):orders_count,@sum(orders.total):total_spent", "@group": "users.id,users.name,users.email", "@order": "total_spent:desc", "@having": "orders_count(gt)=0" }

📊 Пример 4: Сложный JOIN с фильтрацией

Заказы за последний месяц с детализацией:

POST /api/list/orders { "@join": [ "left:users[orders.user_id=users.id]", "left:products[orders.product_id=products.id]", "left:payments[orders.id=payments.order_id]" ], "@return": "orders.id,orders.created_at,users.name:customer,users.email,products.name:product,orders.total,payments.status:payment_status", "@and": [ {"orders.created_at(gte)": "2025-10-01"}, {"orders.status": "completed"} ], "@order": "orders.created_at:desc", "@page": 1, "@size": 50 }

Работа с полями из JOIN таблиц

Фильтрация по полям JOIN таблиц:

POST /api/list/orders { "@join": ["left:users[orders.user_id=users.id]"], "users.email(like)": "%@gmail.com", "users.status": "active", "@return": "orders.*,users.name,users.email" }

Сортировка по полям JOIN таблиц:

@join=["left:users[orders.user_id=users.id]"]&@order=users.name:asc,orders.created_at:desc

Группировка с JOIN:

POST /api/list/orders { "@join": ["left:products[orders.product_id=products.id]"], "@group": "products.id,products.name", "@return": "products.name:product,@count(orders.id):total_orders,@sum(orders.total):revenue", "@order": "revenue:desc" }

Выбор полей при использовании JOIN

Выбрать все поля из основной таблицы:

@return=orders.*,users.name,users.email

Выбрать все поля из всех таблиц:

@return=orders.*,users.*,products.*

⚠️ Не рекомендуется - возвращает много данных

Выбрать конкретные поля с псевдонимами:

@return=orders.id:order_id,orders.total,users.name:customer_name,users.email:customer_email,products.name:product_title

✅ Рекомендуется - явное указание нужных полей

Если @return (и запасной @select) не указаны:

API автоматически вернет все поля из всех таблиц (основной + все JOIN)

❌ Частые ошибки при работе с JOIN

1. Неправильный формат условия связи

❌ Неверно: @join=["left:users[user_id=id]"]

✅ Верно: @join=["left:users[orders.user_id=users.id]"]

Нужно указывать таблицу для каждого поля

2. Забыли указать @return

Без @return (и без запасного @select) вернутся все поля из всех таблиц, что может быть избыточно

3. Неправильный порядок JOIN

Порядок JOIN важен! Сначала присоединяйте таблицы первого уровня, потом второго

4. Дублирование имен полей

Если в разных таблицах есть поля с одинаковыми именами, используйте псевдонимы

@return=orders.id:order_id,users.id:user_id

⚡ Советы по производительности

  • ✅ Используйте @return для выбора только нужных полей
  • ✅ Добавляйте индексы на поля, используемые в условиях JOIN
  • ✅ Используйте фильтрацию для уменьшения количества данных до JOIN
  • ✅ Предпочитайте INNER JOIN, если не нужны записи без совпадений
  • ✅ Ограничивайте результаты с помощью @limit или @page/@size
  • ⚠️ Избегайте JOIN более 4-5 таблиц в одном запросе
  • ⚠️ Не используйте table.* для всех JOIN таблиц одновременно

Поля ответа (@return)

Параметр @return — основной способ задать проекцию: какие столбцы попадают в запрос к данным и какие ключи получает клиент. Список полей задаётся через запятую; синтаксис тот же, что раньше у @select: псевдонимы источник:alias, агрегаты @count, @sum и т.д., пути к вложенным JSON через точку.

Если @return не указан, для обратной совместимости используется параметр @select с тем же форматом списка.

Основной синтаксис

@return=id,name,email,created_at

Псевдонимы полей

Используйте двоеточие для переименования полей в ответе:

@return=id,name:full_name,email:contact_email

Поля из JOIN таблиц

@return=orders.id,users.name:user_name,products.name:product_name

Агрегатные функции

Используйте @ перед именем функции:

@return=category,@count(id):total,@sum(amount):total_amount,@avg(price):avg_price

Доступные функции: @count, @sum, @avg, @min, @max. С @group — агрегаты по каждой группе; с @supress на листе только объект-итог без массива записей.

Выбор всех полей таблицы

@return=users.*,orders.id,orders.total

CREATE, UPDATE, DELETE, SAVE

В этих операциях @return задаёт, какие поля затронутой записи включить в ответ (подмножество доступных полей после операции).

Использование в CREATE

POST /api/create/users { "@set": { "name": "Иван Иванов", "email": "ivan@example.com" }, "@return": "id,name,email,created_at" }

API вернет только указанные поля созданной записи.

Использование в UPDATE

POST /api/update/users { "status": "active", "@set": { "last_login": "2025-11-11" }, "@return": "id,name,status,last_login" }

Возвращает только указанные поля всех обновленных записей.

Использование в LIST

GET /api/list/users?status=active&@return=id,name,email

Формат значения

Поля перечисляются через запятую (в теле POST — строка или массив, в зависимости от клиента):

@return=id,name,email,profile.avatar,created_at

Запасной параметр @select

  • @return — приоритетный список проекции и ключей ответа для list/read и драйверов с SQL-подобной выборкой.
  • @select — учитывается только если @return пустой или отсутствует; нужен для старых интеграций.

Сортировка

Параметр `@order` (или `@sort`) упорядочивает результаты по одному или нескольким полям.

Простая сортировка

Сортировка по одному полю (по умолчанию по возрастанию):

@order=created_at

Указание направления

Используйте `:asc` для возрастания или `:desc` для убывания:

@order=price:desc

Можно использовать короткие формы: `:d` вместо `:desc`

Множественная сортировка

Сортировка по нескольким полям через запятую:

@order=priority:desc,created_at:asc,name

Записи будут отсортированы сначала по приоритету (убывание), затем по дате создания (возрастание), затем по имени.

Сортировка JOIN полей

@order=users.created_at:desc,orders.total:desc

Сортировка JSON полей

Используйте dot notation для JSON полей:

@order=profile.rating:desc,settings.priority

Случайный порядок (@rand)

Для выборок list перемешивает строки результата. При указании @rand параметры @order и @sort для этого запроса не используются.

GET /api/list/dictionary?@rand=1&@limit=20

В POST/JSON: "@rand": true. Включение: @rand=1, @rand=true, @rand=yes или параметр без значения. Выключение: @rand=0, @rand=false.

Нативная реализация: в MySQL добавляется ORDER BY RAND() (для запросов подсчёта записей сортировка не задаётся). В JSON-драйвере — shuffle() по отфильтрованному массиву. Проверка значения: apiFunc::isRandRequested() в api_functions.php.

Группировка и агрегация

Используйте `@group` для группировки результатов и агрегатные функции в `@return` (или в запасном `@select`, если `@return` не задан). Параметр `@having` фильтрует сгруппированные результаты. Модификатор `@supress` убирает массив записей на листе группы — остаются только итоги.

Простая группировка

Группировка по одному полю с подсчетом:

@group=category&@return=category,@count(id):total

@supress — итоги без списка записей

Совместно с @group: на листьях группы вместо массива записей возвращается один объект с полями группировки и агрегатами. Удобно для отчётов «только счётчики/суммы», когда не нужен полный список строк внутри каждой группы.

@group=category&@return=category,@count(id):total&@supress=1

В POST/JSON: "@supress": true. Включение: @supress=1, @supress=true, yes, on или параметр без значения. Выключение: @supress=0, @supress=false, no, off.

Без @supress лист группы — массив записей (с агрегатами, продублированными в каждой строке). С @supress — один объект-итог:

{ "CategoryA": { "category": "CategoryA", "total": 5 }, "CategoryB": { "category": "CategoryB", "total": 12 } }

Без агрегатов в проекции в итог попадает поле __records — число строк в группе. Работает в MySQL- и JSON-драйверах. Логика: apiFunc::isSuppressRequested(), агрегация — класс apiGroupResult в api_functions.php.

Сочетается с @having и вложенной группировкой — @supress применяется только на листьях, промежуточные уровни остаются объектами с ключами подгрупп:

@group=category,status&@return=category,status,@count(id):total&@supress=1&@having=total(gt)=5

Агрегатные функции

Функция Описание Пример
`@count(field)`Количество записей@count(id):total_users
`@sum(field)`Сумма значений@sum(amount):total_amount
`@avg(field)`Среднее значение@avg(price):avg_price
`@min(field)`Минимальное значение@min(price):min_price
`@max(field)`Максимальное значение@max(date):latest_date

Множественная группировка

Группировка по нескольким полям:

@group=category,status&@return=category,status,@count(id):total

Фильтрация с @having

Фильтруйте сгруппированные результаты по агрегатным значениям:

@group=category&@return=category,@count(id):total&@having=total(gt)=5

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

Комплексный пример

Статистика продаж по категориям и статусам:

@group=category,status &@return=category,status,@count(id):total_orders,@sum(amount):total_sales,@avg(amount):avg_order &@having=total_orders(gte)=10 &@order=total_sales:desc

Работа с JSON полями

API поддерживает специальное поле `_json` для хранения произвольных данных и автоматически обрабатывает вложенные структуры.

Автоматическое поднятие полей

Поля из `_json` автоматически становятся доступными на верхнем уровне:

// Структура в БД: { "id": "user123", "name": "Иван", "_json": { "avatar": "http://...", "bio": "Программист" } } // API вернет: { "id": "user123", "name": "Иван", "avatar": "http://...", "bio": "Программист" }

Dot notation для фильтрации

Используйте точечную нотацию для доступа к вложенным полям:

// Фильтр по вложенному полю profile.settings.theme=dark // Фильтр по полю в массиве tags.0=important

Dot notation в @set

При создании или обновлении используйте dot notation для вложенных структур:

POST /api/update/users/user123 { "@set": { "profile.avatar.url": "http://example.com/avatar.jpg", "profile.avatar.size": 1024, "settings.notifications.email": true } }

Это создаст или обновит вложенную структуру в поле _json.

Выбор JSON полей в @return

@return=id,name,profile.avatar,settings.theme

Комплексные примеры

Практические примеры использования API для решения реальных задач.

Пример 1: Поиск активных пользователей с JOIN

Получить список активных пользователей с их заказами, отсортированных по дате регистрации:

GET /api/list/users?status=active&@join=["left:orders[users.id=orders.user_id]"]&@return=users.id,users.name,users.email,orders.total:order_total&@order=users.created_at:desc&@page=1&@size=20

Пример 2: Создание пользователя с вложенным профилем

Создать нового пользователя с профилем и настройками:

POST /api/create/users Content-Type: application/json { "@set": { "name": "Иван Иванов", "email": "ivan@example.com", "status": "active", "profile.avatar": "https://example.com/avatar.jpg", "profile.bio": "Разработчик", "settings.theme": "dark", "settings.notifications.email": true, "settings.notifications.push": false }, "@return": "id,name,email,profile,settings,created_at" }

Пример 3: Сложная фильтрация с логическими операциями

Найти заказы со сложными условиями:

POST /api/list/orders Content-Type: application/json { "@and": [ { "@or": [ {"status": "pending"}, {"status": "processing"} ] }, {"total(gte)": 100}, {"created_at(gte)": "2025-01-01"} ], "@order": "created_at:desc", "@page": 1, "@size": 50 }

Пример 4: Статистика с группировкой

Получить статистику продаж по категориям:

GET /api/list/orders?@group=category,status&@return=category,status,@count(id):total_orders,@sum(total):revenue,@avg(total):avg_order_value&@having=total_orders(gte)=10&@order=revenue:desc

Пример 4.1: Итоги по группам без списка записей (@supress)

Счётчики по типам записей — только агрегаты, без массива строк внутри группы:

GET /api/list/dictionary?@group=entry_type&@return=entry_type,@count(id):total&@supress=1

Ответ: {"word": {"entry_type": "word", "total": 271}, "phrase": {...}}

Пример 5: Массовое обновление с условием (POST)

Обновить статус всех неактивных пользователей:

POST /api/update/users { "last_login(lt)": "2024-01-01", "status": "active", "@set": { "status": "inactive", "deactivated_at": "2025-11-11" }, "@return": "id,name,email,status" }

Пример 5.1: Обновление через GET с @set

Быстрое обновление одной записи через GET запрос:

GET /api/update/users/user123?@set=status=verified&role=premium&last_seen=2025-11-11&@return=id,name,status,role

То же самое с квадратными скобками (рекомендуется для читаемости):

GET /api/update/users/user123?@set=[status=verified&role=premium&last_seen=2025-11-11]&@return=id,name,status,role

Обновление токенов (реальный пример):

GET /api/update/users/user123?@set=[firebaseToken=abc123xyz&mobileFirebaseToken=mobile456def&webToken=web789ghi]&@return=id,name,firebaseToken

Обновление вложенных JSON полей через GET:

GET /api/update/users/user123?@set=[profile.avatar.url=https://cdn.example.com/avatar.jpg&profile.avatar.size=2048&settings.theme=dark]&@return=profile,settings

Массовое обновление с условиями через GET:

GET /api/update/orders?status=pending&created_at(lt)=2025-01-01&@set=[status=cancelled&cancelled_reason=Expired]&@return=id,status,cancelled_reason

✅ Преимущества квадратных скобок:

  • Чёткое визуальное отделение параметров @set от условий фильтрации
  • Улучшенная читаемость при большом количестве полей
  • Уменьшение ошибок при формировании URL

💡 GET запросы удобны для простых обновлений и могут быть легко использованы в URL, но для сложных операций рекомендуется POST.

Пример 6: Поиск по вложенным JSON полям

Найти пользователей с определенными настройками:

POST /api/list/users { "settings.theme": "dark", "profile.verified": true, "tags(in)": ["premium", "verified"], "@return": "id,name,email,profile.avatar,settings.theme" }

Пример 7: Работа с пустыми значениями

Найти пользователей без аватара или биографии:

GET /api/list/users?@or=(profile.avatar(empty)=true&profile.bio(empty)=true)&status=active&@return=id,name,email,profile

Пример 8: Операция SAVE (создать или обновить)

Создать или обновить пользователя:

POST /api/save/users { "@set": { "id": "user123", "name": "Иван Иванов (обновлено)", "email": "ivan.new@example.com", "profile.updated_at": "2025-11-11" }, "@return": "id,name,email,created_at,updated_at" }

Сохранение вложенного JSON-фрагмента (настройки модуля courses в записи settings/modules):

POST /api/save/settings/modules/courses { "courses": [{"id": 1, "name": "Курс A"}], "expert": true, "time": 60 }

Если user123 существует — обновит, если нет — создаст. Для field в URL вложенный объект заменяется целиком.

Интерактивный конструктор запросов

Используйте эту форму, чтобы визуально построить ваш API-запрос. URL и команда cURL будут сгенерированы автоматически.

Фильтры

Сгенерированные запросы

GET-запрос (cURL с Bearer)

GET-запрос (URL без токена)

POST-запрос (cURL)

1