Skip to content
  1. Компоненты
  2. MiniShop3
  3. Разработка
  4. API Router

API Router ​

MiniShop3 использует библиотеку FastRoute для маршрутизации API запросов. Компонент предоставляет два отдельных API с различными механизмами авторизации.

Архитектура ​

Два типа API ​

ПараметрManager APIWeb API
Префикс/api/mgr/*/api/v1/*
НазначениеАдминистративная панель MODXФронтенд магазина
Entry pointconnector.phpassets/.../api.php
АвторизацияMODX сессии + HTTP_MODAUTHТокены MS3TOKEN
MiddlewareAuthMiddleware, PermissionMiddlewareTokenMiddleware, CorsMiddleware, RateLimitMiddleware
Файл роутовconfig/routes/manager.phpconfig/routes/web.php

Структура файлов ​

core/components/minishop3/
├── config/
│   ├── routes/
│   │   ├── manager.php                    # Системные роуты Manager API
│   │   └── web.php                        # Системные роуты Web API
│   ├── ms3.routes.d/
│   │   ├── manager/example-addon.php.dist # Пример для аддонов (Manager)
│   │   └── web/example-addon.php.dist     # Пример для аддонов (Web)
│   └── routes_manager.custom.example.php  # Пример кастомных роутов

core/config/
├── ms3_routes_manager.custom.php          # Кастомные Manager роуты
├── ms3_routes_web.custom.php              # Кастомные Web роуты
└── ms3.routes.d/                          # Модульные роуты аддонов
    ├── manager/                           # Manager API фрагменты
    └── web/                               # Web API фрагменты

Базовое использование ​

Определение роутов ​

php
use MiniShop3\Router\Response;

// Простой GET роут
$router->get('/api/mgr/my-endpoint', function($params) use ($modx) {
    return Response::success(['data' => 'value']);
});

// POST роут
$router->post('/api/mgr/items', function($params) use ($modx) {
    $data = json_decode(file_get_contents('php://input'), true);
    return Response::success(['created' => true]);
});

// PUT роут
$router->put('/api/mgr/items/{id}', function($params) use ($modx) {
    $id = $params['id'];
    return Response::success(['updated' => $id]);
});

// DELETE роут
$router->delete('/api/mgr/items/{id}', function($params) use ($modx) {
    return Response::success(['deleted' => true]);
});

Параметры URL ​

php
// Один параметр
$router->get('/api/mgr/products/{id}', function($params) use ($modx) {
    $id = $params['id'];  // Значение из URL
    return Response::success(['product_id' => $id]);
});

// Несколько параметров
$router->get('/api/mgr/orders/{order_id}/products/{product_id}', function($params) use ($modx) {
    $orderId = $params['order_id'];
    $productId = $params['product_id'];
    return Response::success([
        'order_id' => $orderId,
        'product_id' => $productId
    ]);
});

Группировка роутов ​

php
use MiniShop3\Router\Middleware\AuthMiddleware;
use MiniShop3\Router\Middleware\PermissionMiddleware;

$router->group('/api/mgr/catalog', function($router) use ($modx) {

    // GET /api/mgr/catalog/products
    $router->get('/products', function($params) use ($modx) {
        return Response::success(['products' => []]);
    });

    // GET /api/mgr/catalog/categories
    $router->get('/categories', function($params) use ($modx) {
        return Response::success(['categories' => []]);
    });

    // POST /api/mgr/catalog/products
    $router->post('/products', function($params) use ($modx) {
        return Response::success(['created' => true]);
    });

}, [
    // Middleware для всей группы
    new AuthMiddleware($modx, 'mgr'),
    new PermissionMiddleware($modx, 'msproduct_save')
]);

Контроллеры ​

Для сложной логики рекомендуется использовать контроллеры:

php
$router->group('/api/mgr/orders', function($router) use ($modx) {

    $router->get('', function($params) use ($modx) {
        $controller = new \MiniShop3\Controllers\Api\Manager\OrdersController($modx);
        return $controller->getList($params);
    });

    $router->get('/{id}', function($params) use ($modx) {
        $controller = new \MiniShop3\Controllers\Api\Manager\OrdersController($modx);
        return $controller->get($params);
    });

    $router->put('/{id}', function($params) use ($modx) {
        $body = json_decode(file_get_contents('php://input'), true) ?: [];
        $allParams = array_merge($params, $body);

        $controller = new \MiniShop3\Controllers\Api\Manager\OrdersController($modx);
        return $controller->update($allParams);
    });

});

Response ​

Все API endpoints возвращают JSON ответы через класс MiniShop3\Router\Response:

php
use MiniShop3\Router\Response;

// Успешный ответ
Response::success($data, $message, $statusCode);

// Ответ с ошибкой
Response::error($message, $statusCode, $errors);

Формат ответа ​

Успешный ответ:

json
{
  "success": true,
  "message": "Operation completed",
  "data": {
    "id": 123,
    "name": "Product"
  }
}

Ответ с ошибкой:

json
{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "name": "Field is required"
  }
}

HTTP коды ответов ​

КодОписаниеИспользование
200OKУспешный запрос
400Bad RequestОшибка валидации
401UnauthorizedНе авторизован
403ForbiddenНет прав доступа
404Not FoundРоут или ресурс не найден
405Method Not AllowedМетод не разрешён
429Too Many RequestsПревышен лимит запросов
500Internal Server ErrorВнутренняя ошибка

Middleware ​

Middleware выполняются последовательно перед обработчиком роута. Если middleware возвращает Response, выполнение прерывается.

Интерфейс ​

php
namespace MiniShop3\Router\Middleware;

interface MiddlewareInterface
{
    /**
     * @param array $params URL параметры
     * @return Response|null Response для прерывания, null для продолжения
     */
    public function handle(array $params);
}

Встроенные middleware ​

AuthMiddleware ​

Проверяет авторизацию пользователя MODX. Для контекста mgr дополнительно проверяет токен HTTP_MODAUTH.

php
use MiniShop3\Router\Middleware\AuthMiddleware;

// Проверка авторизации в админке
$router->get('/api/mgr/secure', function($params) use ($modx) {
    return Response::success(['user' => $modx->user->get('username')]);
}, [
    new AuthMiddleware($modx, 'mgr')  // 'mgr' или 'web'
]);

Проверки:

  • Наличие авторизованного пользователя $modx->user
  • Для mgr: валидность токена HTTP_MODAUTH

PermissionMiddleware ​

Проверяет права доступа пользователя через $modx->hasPermission().

php
use MiniShop3\Router\Middleware\PermissionMiddleware;

$router->post('/api/mgr/products', function($params) use ($modx) {
    // Создание товара
}, [
    new PermissionMiddleware($modx, 'msproduct_save')
]);

Основные права MiniShop3:

  • msproduct_save — создание/редактирование товаров
  • mssetting_save — управление настройками (доставки, оплаты, производители, уведомления)
  • view_document — чтение категорий и гридов товаров в категории
  • msorder_list — список заказов и клиентов, адреса клиента (GET)
  • msorder_view — просмотр карточки клиента
  • msorder_save — изменение заказов и клиентов, мутации позиций заказа
  • msorder_remove — удаление заказов, клиентов, массовое удаление

TokenMiddleware ​

Проверяет и при необходимости auto-mint токен покупателя для Web API.

Порядок resolve: Authorization: Bearer → заголовок MS3TOKEN (legacy) → httpOnly cookie ms3_token → $_REQUEST → session. Query token / ms3_token снимаются и не принимаются.

php
use MiniShop3\Middleware\TokenMiddleware;

$tokenMiddleware = new TokenMiddleware($modx);

$router->group('/api/v1/cart', function($router) use ($modx) {
    // Роуты корзины
}, [$tokenMiddleware]);

На роутах с middleware без валидного токена сервер auto-mint гостевой токен (кроме путей из publicRoutes middleware, например logout). Каталог, health и token/get в web.php middleware не вешают.

Подробнее: Авторизация Web API.

CorsMiddleware ​

Настраивает CORS заголовки для кросс-доменных запросов.

php
use MiniShop3\Middleware\CorsMiddleware;

$corsMiddleware = new CorsMiddleware([
    'allowed_origins' => ['https://shop.example.com', 'https://admin.example.com'],
    'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    'allowed_headers' => ['Content-Type', 'Authorization', 'MS3TOKEN'],
    'allow_credentials' => true,
    'max_age' => 86400  // Кеш preflight запросов (24 часа)
]);

Системная настройка: ms3_cors_allowed_origins. Пусто = same-origin; * = любой origin без credentials; список доменов нужен для cookie с другого origin. См. CORS.

RateLimitMiddleware ​

Ограничивает количество запросов для защиты от злоупотреблений.

php
use MiniShop3\Middleware\RateLimitMiddleware;

$rateLimitMiddleware = new RateLimitMiddleware(
    60,   // Максимум 60 запросов
    60    // За 60 секунд
);

Системные настройки:

  • ms3_rate_limit_max_attempts — максимум запросов (по умолчанию: 60)
  • ms3_rate_limit_decay_seconds — период в секундах (по умолчанию: 60)

Заголовки ответа:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1703001234

Создание своего middleware ​

php
<?php
namespace MyComponent\Middleware;

use MiniShop3\Router\Middleware\MiddlewareInterface;
use MiniShop3\Router\Response;
use MODX\Revolution\modX;

class LoggingMiddleware implements MiddlewareInterface
{
    private modX $modx;

    public function __construct(modX $modx)
    {
        $this->modx = $modx;
    }

    public function handle(array $params)
    {
        // Логирование запроса
        $this->modx->log(
            modX::LOG_LEVEL_INFO,
            sprintf(
                '[API] %s %s from %s',
                $_SERVER['REQUEST_METHOD'],
                $_SERVER['REQUEST_URI'],
                $_SERVER['REMOTE_ADDR']
            )
        );

        // null = продолжить выполнение
        return null;
    }
}

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

php
use MyComponent\Middleware\LoggingMiddleware;

$router->get('/api/mgr/logged-endpoint', function($params) use ($modx) {
    return Response::success(['logged' => true]);
}, [
    new LoggingMiddleware($modx),
    new AuthMiddleware($modx, 'mgr')
]);

Порядок выполнения middleware ​

Middleware выполняются в порядке указания:

php
$router->get('/api/mgr/endpoint', $handler, [
    new CorsMiddleware(),        // 1. Сначала CORS
    new RateLimitMiddleware(),   // 2. Проверка лимита
    new AuthMiddleware($modx),   // 3. Авторизация
    new PermissionMiddleware(),  // 4. Права доступа
]);

При возврате Response из middleware, остальные middleware и обработчик не выполняются.

Карта роутов ​

Manager API (/api/mgr/*) ​

Общие ​

МетодРоутОписание
GET/healthПроверка работоспособности API
GET/user/infoИнформация о текущем пользователе

Конфигурация (/config) ​

МетодРоутОписание
GET/page-fields/{page_key}Получить поля страницы (без mssetting_save)
GET/page-fields/{page_key}/allВсе поля страницы
PUT/page-fields/{page_key}Обновить поля (тело: { "fields": [...] }, нужно mssetting_save)
GET/sections/{page_key}Получить секции
PUT/sections/{page_key}Обновить секции (тело: { "sections": [...] })
DELETE/sections/{page_key}/{section_key}Удалить секцию по ключу

Конфигурация гридов (/grid-config) ​

CRUD для конфига колонок административных гридов. Чтение — view_document, запись — mssetting_save.

МетодРоутОписание
GET/{grid_key}Получить конфигурацию грида
PUT/{grid_key}Обновить конфигурацию грида (тело: fields)
POST/{grid_key}/fieldДобавить колонку
PUT/{grid_key}/field/{field_name}Обновить колонку
DELETE/{grid_key}/{field_name}Удалить колонку

Известные grid_key в MS3 1.13: orders, order_products, customers, vendors, category-products.

Ответ GET /grid-config/{grid_key} ​
json
{
  "columns": [
    { "name": "id", "label": "ID", "type": "model", "visible": true, ... }
  ],
  "direct_filter_keys": ["query", "status_id", "delivery_id", ...],
  "editor_references": [
    { "key": "vendors", "path": "/api/mgr/references/vendors" }
  ]
}
ПолеТипОписание
columnsarrayКолонки грида с конфигурацией (тип, видимость, фильтрация, редактор)
direct_filter_keysstring[]Ключи фильтров, которые контроллер ждёт как прямые параметры запроса (без префикса filter_). Остальные — отправлять с префиксом. Источник истины — backend; фронт читает массив отсюда. Появилось в MiniShop3 1.12.0 — закрывает дублирование между фронтом и контроллерами.
editor_referencesarray<{key,path}>Только для grid_key=category-products. Whitelist допустимых reference-ключей для combo-редактора inline-edit. Каждая запись — пара ключа и пути к API-эндпойнту справочника. Используется UI настройки колонок для select dropdown. Появилось в MiniShop3 1.12.0.
Контракт фильтров (direct_filter_keys) ​

Фронт-код решает, как сериализовать значение фильтра:

js
// Псевдокод composable useGridFilterParams
function addFilterParam(params, key, value) {
    if (directFilterKeys.has(key)) {
        params[key] = value         // direct: ?status_id=2
    } else {
        params['filter_' + key] = value   // prefixed: ?filter_customer_name=...
    }
}

Это значит — добавляя новый прямой фильтр на бекенде, обязательно дописать его ключ в DIRECT_FILTER_KEYS-константу соответствующего контроллера. Иначе фронт отправит его с префиксом и фильтрация не сработает.

Заказы (/orders) ​

Чтение и запись разделены на две группы middleware.

Чтение — право msorder_list:

МетодРоутОписание
GET``Список заказов
GET/filtersКонфигурация фильтров
GET/statsАгрегаты для дашборда и фильтров
GET/{id}Получить заказ
GET/{id}/productsТовары заказа
GET/{id}/logsИстория изменений

Запись — право msorder_save:

МетодРоутОписание
POST``Создать заказ из менеджера
DELETE/bulkМассовое удаление
POST/{id}/finalizeФинализация черновика
POST/{id}/recalculate-costПересчёт стоимости
PUT/{id}Обновить заказ
DELETE/{id}Удалить заказ
POST/{id}/productsДобавить товар
PUT/{id}/products/{product_id}Обновить позицию
DELETE/{id}/products/{product_id}Удалить позицию

Справочники для форм заказа (без отдельного PermissionMiddleware, сессия mgr):

МетодРоутОписание
GET/statuses-dropdownСтатусы с переводами
GET/deliveries-activeАктивные доставки для select

Покупатели (/customers) ​

МетодРоутОписаниеПраво
GET``Список покупателейmsorder_list
DELETE/bulkМассовое удалениеmsorder_remove
GET/{id}Получить покупателяmsorder_view
PUT/{id}Обновить покупателяmsorder_save
DELETE/{id}Удалить покупателяmsorder_remove
GET/{id}/addressesАдреса покупателяmsorder_list
POST/{id}/addressesДобавить адресmsorder_save
PUT/{id}/addresses/{address_id}Обновить адресmsorder_save
DELETE/{id}/addresses/{address_id}Удалить адресmsorder_remove

Настройки магазина ​

Доставки (/deliveries), Оплаты (/payments), Производители (/vendors), Статусы (/statuses), Связи (/links) — CRUD операции с правом mssetting_save.

Данные товара (/product-data) ​

Вкладки «Категории» и «Связи» на карточке товара (Vue). Право msproduct_save / сессия mgr:

МетодРоутОписание
GET/{id}/categories/treeДерево категорий (ms3_product_category_tree)
GET/{id}/linksСписок связей
POST/{id}/linksДобавить связь { slave, link }
DELETE/{id}/linksУдалить связь { link, master, slave }
GET/references/link-typesТипы msLink (группа references)
GET/references/productsAutocomplete товаров

Уведомления (/notifications) ​

МетодРоутОписаниеПраво
GET/referencesСправочники для формmssetting_save
GET``Список уведомленийmssetting_save
GET/{id}Получить уведомлениеmssetting_save
POST``Создать уведомлениеmssetting_save
PUT/{id}Обновитьmssetting_save
DELETE/{id}Удалитьmssetting_save

Импорт (/import) ​

МетодРоутОписаниеПраво
GET/fieldsПоля для маппингаmsproduct_save
POST/uploadЗагрузка CSVmsproduct_save
POST/previewПредпросмотрmsproduct_save
POST/startЗапуск импортаmsproduct_save
GET/progress/{import_id}Прогресс импортаmsproduct_save

Web API (/api/v1/*) ​

Полная таблица путей: Web API → Карта эндпоинтов.

Guides: auth, catalog, cart, checkout, customer.

Кастомизация роутов ​

Добавление своих роутов ​

Создайте файл core/config/ms3_routes_manager.custom.php:

php
<?php
use MiniShop3\Router\Middleware\AuthMiddleware;
use MiniShop3\Router\Middleware\PermissionMiddleware;
use MiniShop3\Router\Response;

// Простой роут
$router->get('/api/mgr/my-custom-endpoint', function() use ($modx) {
    return Response::success(['custom' => true]);
}, [
    new AuthMiddleware($modx, 'mgr')
]);

// Группа роутов
$router->group('/api/mgr/my-module', function($router) use ($modx) {

    $router->get('/dashboard', function() use ($modx) {
        return Response::success([
            'stats' => ['orders' => 100, 'revenue' => 50000]
        ]);
    });

    $router->post('/action', function($params) use ($modx) {
        $data = json_decode(file_get_contents('php://input'), true);
        // Обработка...
        return Response::success(['processed' => true]);
    });

}, [
    new AuthMiddleware($modx, 'mgr'),
    new PermissionMiddleware($modx, 'my_module_permission')
]);

Для Web API создайте core/config/ms3_routes_web.custom.php.

Переопределение системных роутов ​

Кастомные роуты загружаются после системных и переопределяют их:

php
<?php
// core/config/ms3_routes_manager.custom.php

use MiniShop3\Router\Response;

// Переопределение системного роута /api/mgr/health
$router->get('/api/mgr/health', function() use ($modx) {
    return Response::success([
        'status' => 'custom_ok',
        'version' => '1.0.0-custom',
        'timestamp' => time()
    ]);
});

Интеграция со сторонними компонентами ​

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

php
<?php
// core/config/ms3_routes_manager.custom.php

use MiniShop3\Router\Response;
use MiniShop3\Router\Middleware\AuthMiddleware;

// Роуты для компонента msPromoCode
$router->group('/api/mgr/promocodes', function($router) use ($modx) {

    $router->get('', function($params) use ($modx) {
        $codes = $modx->getCollection('msPromoCode');
        $result = [];
        foreach ($codes as $code) {
            $result[] = $code->toArray();
        }
        return Response::success(['codes' => $result]);
    });

    $router->post('', function($params) use ($modx) {
        $data = json_decode(file_get_contents('php://input'), true);

        $code = $modx->newObject('msPromoCode');
        $code->fromArray($data);

        if ($code->save()) {
            return Response::success(['id' => $code->get('id')]);
        }
        return Response::error('Failed to create promo code', 400);
    });

    $router->delete('/{id}', function($params) use ($modx) {
        $code = $modx->getObject('msPromoCode', $params['id']);
        if ($code && $code->remove()) {
            return Response::success(['deleted' => true]);
        }
        return Response::error('Not found', 404);
    });

}, [
    new AuthMiddleware($modx, 'mgr')
]);

Модульные роуты для аддонов (ms3.routes.d) ​

Файлы ms3_routes_*.custom.php подходят для ручной кастомизации, но не для аддонов — если два компонента пишут в один файл, при установке/удалении возникают конфликты.

Для сторонних компонентов предусмотрена директория core/config/ms3.routes.d/ — каждый аддон создаёт свой файл, конфликтов нет.

Аналогия

Паттерн повторяет ms3.services.d/ для сервисов.

Структура ​

core/config/ms3.routes.d/
├── web/                          # Роуты Web API (api.php)
│   ├── 50-mydelivery.php
│   └── 50-mypayment.php
└── manager/                      # Роуты Manager API (connector)
    ├── 50-mydelivery.php
    └── 50-myadmin.php

Файлы загружаются в алфавитном порядке. Используйте числовой префикс для управления приоритетом (01-, 50-, 99-).

Порядок загрузки ​

Web API (api.php):

  1. config/routes/web.php — системные роуты
  2. core/config/ms3_routes_web.custom.php — ручные кастомизации
  3. core/config/ms3.routes.d/web/*.php — аддоны
  4. build() диспетчера

Manager API (connector.php → Processors\Api\Router):

  1. config/routes/manager.php — системные роуты
  2. core/config/ms3_routes_manager.custom.php — ручные кастомизации
  3. core/config/ms3.routes.d/manager/*.php — аддоны
  4. build() диспетчера

Каждый следующий уровень может переопределять роуты предыдущего по ключу METHOD:PATTERN.

Пример: Web API роуты аддона доставки ​

php
<?php
// core/config/ms3.routes.d/web/50-mydelivery.php

use MiniShop3\Router\Response;
use MiniShop3\Middleware\TokenMiddleware;

$router->group('/api/v1/delivery/mydelivery', function ($router) use ($modx) {

    $router->post('/calculate', function (array $vars, \MODX\Revolution\modX $modx) {
        $input = json_decode(file_get_contents('php://input'), true) ?: [];
        $cost = MyDelivery::calculate($input['address'] ?? '', $input['weight'] ?? 0);
        return Response::success(['cost' => $cost]);
    });

    $router->get('/points', function (array $vars, \MODX\Revolution\modX $modx) {
        $city = $vars['city'] ?? '';
        $points = MyDelivery::getPickupPoints($city);
        return Response::success(['points' => $points]);
    });

}, [new TokenMiddleware($modx)]);

Пример: Manager API роуты аддона ​

php
<?php
// core/config/ms3.routes.d/manager/50-mydelivery.php

use MiniShop3\Router\Middleware\AuthMiddleware;
use MiniShop3\Router\Response;

$router->group('/api/mgr/mydelivery', function ($router) use ($modx) {

    $router->get('/settings', function (array $vars, \MODX\Revolution\modX $modx) {
        return Response::success([
            'api_key' => $modx->getOption('mydelivery_api_key'),
            'enabled' => (bool) $modx->getOption('mydelivery_enabled'),
        ]);
    });

    $router->put('/settings', function (array $vars, \MODX\Revolution\modX $modx) {
        $data = json_decode(file_get_contents('php://input'), true) ?: [];
        // Сохранение настроек...
        return Response::success(['saved' => true]);
    });

}, [new AuthMiddleware($modx, 'mgr')]);

Установка и удаление ​

В resolver аддона:

php
<?php
// resolver при установке
$routesDir = MODX_CORE_PATH . 'config/ms3.routes.d/';

// Копируем файл роутов
copy(
    $source . 'routes/web.php',
    $routesDir . 'web/50-mydelivery.php'
);
copy(
    $source . 'routes/manager.php',
    $routesDir . 'manager/50-mydelivery.php'
);
php
<?php
// resolver при удалении
@unlink(MODX_CORE_PATH . 'config/ms3.routes.d/web/50-mydelivery.php');
@unlink(MODX_CORE_PATH . 'config/ms3.routes.d/manager/50-mydelivery.php');

Каждый аддон удаляет только свой файл — другие аддоны не затрагиваются.

Обработка ошибок ​

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

[MiniShop3 Router] Failed to load routes file /path/to/50-broken.php: syntax error...

Custom-файл vs ms3.routes.d ​

ms3_routes_*.custom.phpms3.routes.d/
Для когоРазработчик сайтаАвторы аддонов
ФайловОдин на тип APIПо файлу на аддон
КонфликтыВозможны при нескольких аддонахНет
Install/uninstallНужно редактировать вручнуюАтомарный: создать/удалить файл
СоздаётсяПри установке ms3 (example)Аддон через resolver

Системные настройки ​

НастройкаПо умолчаниюОписание
ms3_cors_allowed_origins["*"]Разрешённые домены для CORS
ms3_rate_limit_max_attempts60Лимит запросов
ms3_rate_limit_decay_seconds60Период сброса лимита (сек)

Отладка ​

Логирование запросов ​

php
$router->get('/api/mgr/debug', function($params) use ($modx) {
    $modx->log(
        \MODX\Revolution\modX::LOG_LEVEL_INFO,
        '[API Debug] ' . json_encode([
            'method' => $_SERVER['REQUEST_METHOD'],
            'uri' => $_SERVER['REQUEST_URI'],
            'params' => $params,
            'body' => file_get_contents('php://input')
        ])
    );

    return Response::success(['debug' => true]);
});

Типичные ошибки ​

401 Unauthorized:

  • Не авторизован в MODX
  • Отсутствует или невалидный HTTP_MODAUTH токен
  • Для Web API: отсутствует или истёк MS3TOKEN

403 Forbidden:

  • Нет права доступа (проверьте ACL пользователя)

404 Not Found:

  • Роут не зарегистрирован
  • Опечатка в URL

405 Method Not Allowed:

  • Используется неправильный HTTP метод (GET вместо POST и т.д.)

429 Too Many Requests:

  • Превышен лимит запросов, подождите Retry-After секунд