Введение

Этот документ описывает синтаксис для выполнения запросов к нашему 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 доступен без проверки токена. При включённой защите запросы без Bearer получают права роли unknown (Guest).

  4. Guest — unknown (вверху списка, readonly)

    Права для посетителей без login: list/read только для выбранных таблиц (по умолчанию pages, catalogs). Токен не требуется.

  5. Нажмите "+ Add Token" для создания нового токена
  6. Заполните параметры токена:
    • Token nameadmin для полного доступа; любое другое имя — пользовательский токен (_owner = имя при ownership)
    • Token — сам токен (кнопка 🔄 для автогенерации)
    • Default — общие права по умолчанию для всех таблиц: C Create, R Read, U Update, D Delete, S Save, L List
    • Table-specific permissions — при необходимости задайте переопределения прав для отдельных таблиц (например, для таблицы users только L). Если переопределения нет, используются права по умолчанию
  7. Нажмите "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
  • Регулярно меняйте токены для критичных систем
  • Используйте разные токены для разных приложений
  • Настраивайте минимальные необходимые разрешения (принцип наименьших привилегий)

Доступ: Guest, Token, Ownership

Три слоя для HTTP-запросов. Internal PHP ($api->list(), internalRequest()) — без ограничений.

Pipeline

enforceProtection → enforceOwnership → field filter (request/response)
  • Protect + Token — Bearer, CRUDSL (access, table_access), whitelist полей
  • Ownership — строки по _owner, list_scope, owner_ops
  • Fields — пересечение полей токена и ownership для non-admin

Guest (unknown)

Readonly-токен вверху Security. Запрос без Bearer → Guest.

  • Table-specific: таблицы + l/r + Fields
  • Non-admin: на owned-таблицах list_scope: own → только _owner = "unknown"
  • protect: true — неверный Bearer → 403; без Bearer → Guest (не блокируется)

Токены

ИмяOwnership / Fields
adminбез ownership, все поля
unknownGuest; ownership + fields как у user
любое другое_owner = name; CRUDSL + table_access + Fields

Только Authorization: Bearer. Пустой fields = все поля (с учётом ownership).

Ownership

  • list_scope: own — list/count/read: _owner = token.name
  • owner_ops — права владельца строки; admin не ограничен
  • create/save (HTTP non-admin): _owner ставится автоматически
  • ownership.tables.*.fieldstable_access.fields

Полное руководство: docs/api-access-control.md в репозитории API.

Ownership (_owner)

Row-level ACL для HTTP non-admin (включая Guest). Настройка: /api/settingsOwnership.

Иерархия

  • Internal PHP — полный доступ, без Bearer и без ownership
  • HTTP + admin — scope токена; owner_ops не ограничивают
  • HTTP + non-admin (Guest и именованные токены) — _owner = token.name; write = scope ∩ owner_ops

Пример api.json

{ "ownership": { "enabled": true, "tables": { "members": { "list_scope": "own", "owner_ops": { "r": true, "u": true, "d": false, "c": true, "s": true } } } }, "tokens": [{ "name": "42", "value": "...", "access": ["r", "l", "u"] }] }

Действия (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. В GET элементы через запятую в [...] без кавычек: @join=[left:users[orders.user_id=users.id],inner:products[...]]. В POST/JSON — массив строк.

Формат:

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

Без alias@ псевдоним = имя таблицы. Для двух JOIN к одной таблице — обязателен уникальный alias (course_ref@courses).

Тип JOIN

inner, left, right, full

Таблица

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

Условие

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

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

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

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

JOIN alias (одна таблица дважды)

Если одну таблицу нужно присоединить по разным полям, укажите SQL-alias через @:

@join=[inner:course_ref@courses[courses_works.course=course_ref.id],left:lesson_ref@courses[courses_works.practicle=lesson_ref.id]]
@return=course_ref.header:course_name,lesson_ref.header:lesson_name

В проекции и сортировке используйте alias (course_ref.header), не имя таблицы. Повтор таблицы без alias — ошибка.

Типы 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. JOIN к таблице вместо элемента JSON-массива

left:div@courses[c2.division=div.id] — если division это id внутри c1.divides[], а не courses.id

@return=c1.divides[id=c2.division].name:division_name — см. раздел «Поля ответа (@return)» → array pick

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

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

@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

Выборка элемента из JSON-массива (array pick)

Когда связанное значение лежит внутри массива в _json joined-записи, а не в отдельной строке таблицы:

Формат: alias.arrayField[matchKey=matchRef].pickField[:outputAlias]

  • alias — JOIN-alias источника массива (например c1)
  • arrayField — имя массива в JSON (divides)
  • matchKey — поле элемента для сравнения (id)
  • matchRef — dot-path к значению (c2.division — может быть другой alias)
  • pickField — поле элемента в ответ (name)
GET /api/list/courses_works?@join=[inner:c1@courses[course=c1.id],inner:c2@courses[practicle=c2.id]]&@return=id,c1.header:course_name,c1.divides[id=c2.division].name:division_name,c2.header:practicle_name

MySQL: подзапрос JSON_TABLE; JsonDriver: apiFunc::pickFromJsonArray(). Не путать с JOIN к таблице — id из divides[] не является courses.id.

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

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

@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` убирает массив записей на листе группы — остаются только итоги.

@pick / @latest — одна полная строка на группу

В отличие от @group + @max(field) (агрегат), @pick возвращает целую исходную запись с MAX/MIN поля на каждую группу — плоский список, не вложенное дерево. Требует @group. При ничьей — больший id. @limit/@size — после выбора победителей.

@group=room&@pick=timedate:max&@return=id,room,member,timedate,message,userdata

Алиасы направления: max/d/desc, min/a/asc. Короткий алиас: @latest=timedate@pick=timedate:max.

GET /api/list/synapse?room(in)=[id1,id2]&@group=room&@pick=timedate:max&@return=id,room,member,timedate,message,userdata

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

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

@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