Разработка REST API для сайта на 1С-Битрикс
Битрикс имеет встроенный REST API для Битрикс24, но для сайта на «1С-Битрикс: Управление сайтом» собственного REST нет — его нужно строить. Задача возникает регулярно: мобильное приложение требует данные каталога, сторонний сервис хочет получать заказы, фронтенд на React или Vue нужно снабжать данными без перезагрузки страницы. Разберём, как построить API на D7, который выдержит нагрузку и не превратится в помойку через полгода.
Архитектура: Controller + Router
Основа API — контроллеры на базе \Bitrix\Main\Engine\Controller. Каждый контроллер отвечает за один ресурс:
/local/modules/my.api/lib/
├── Controllers/
│ ├── ProductController.php → GET /api/v1/products
│ ├── OrderController.php → GET/POST /api/v1/orders
│ ├── CategoryController.php → GET /api/v1/categories
│ └── AuthController.php → POST /api/v1/auth/token
├── Services/
│ ├── ProductService.php
│ └── OrderService.php
├── Transformers/
│ ├── ProductTransformer.php → форматирование ответа
│ └── OrderTransformer.php
└── Middleware/
├── AuthMiddleware.php
└── RateLimitMiddleware.php
Реализация контроллера
namespace MyApi\Controllers;
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Engine\ActionFilter;
use MyApi\Services\ProductService;
use MyApi\Middleware\AuthMiddleware;
class ProductController extends Controller
{
public function configureActions(): array
{
return [
'list' => ['prefilters' => [new AuthMiddleware()]],
'detail' => ['prefilters' => [new AuthMiddleware()]],
'create' => ['prefilters' => [new AuthMiddleware(), new ActionFilter\HttpMethod(['POST'])]],
];
}
public function listAction(int $page = 1, int $perPage = 20, string $category = ''): array
{
$service = new ProductService();
$result = $service->getList($page, $perPage, $category);
return [
'data' => $result['items'],
'meta' => [
'total' => $result['total'],
'page' => $page,
'per_page' => $perPage,
'pages' => ceil($result['total'] / $perPage),
],
];
}
public function detailAction(int $id): array
{
$service = new ProductService();
$product = $service->getById($id);
if (!$product) {
$this->addError(new \Bitrix\Main\Error('Товар не найден', 404));
return [];
}
return ['data' => $product];
}
}
Аутентификация
API-ключи — простейший вариант для server-to-server интеграций:
namespace MyApi\Middleware;
use Bitrix\Main\Engine\ActionFilter\Base;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
class AuthMiddleware extends Base
{
public function onBeforeAction(Event $event): ?EventResult
{
$request = \Bitrix\Main\Application::getInstance()->getContext()->getRequest();
$apiKey = $request->getHeader('X-Api-Key');
$validKey = \Bitrix\Main\Config\Option::get('my.api', 'api_key');
if ($apiKey !== $validKey) {
$this->addError(new \Bitrix\Main\Error('Unauthorized', 401));
return new EventResult(EventResult::ERROR);
}
return null;
}
}
JWT — для пользовательских запросов (mobile app, SPA). Библиотека firebase/php-jwt через Composer в /local/:
$decoded = \Firebase\JWT\JWT::decode(
substr($authHeader, 7), // убираем 'Bearer '
new \Firebase\JWT\Key($secret, 'HS256')
);
$userId = (int)$decoded->sub;
Токены хранятся на клиенте. Refresh-токены сохраняются в b_option или в кастомной ORM-таблице с привязкой к пользователю.
Формат ответов
Консистентный формат — залог предсказуемого поведения API:
// Успешный ответ
{
"status": "ok",
"data": { ... },
"meta": { "total": 150, "page": 1 }
}
// Ошибка
{
"status": "error",
"errors": [
{ "code": "NOT_FOUND", "message": "Товар не найден" }
]
}
Битрикс-контроллер формирует ответ автоматически, но формат по умолчанию специфичен. Для полного контроля — переопределяем processAfterAction:
protected function processAfterAction(Action $action, $result)
{
$response = \Bitrix\Main\Application::getInstance()->getContext()->getResponse();
$response->addHeader('Content-Type', 'application/json; charset=utf-8');
if ($this->getErrors()) {
echo json_encode([
'status' => 'error',
'errors' => array_map(fn($e) => [
'code' => $e->getCode(),
'message' => $e->getMessage(),
], $this->getErrors()),
], JSON_UNESCAPED_UNICODE);
} else {
echo json_encode([
'status' => 'ok',
'data' => $result,
], JSON_UNESCAPED_UNICODE);
}
exit;
}
CORS
Для API, который вызывается с другого домена:
// В начале контроллера или в отдельном middleware
$response = \Bitrix\Main\Application::getInstance()->getContext()->getResponse();
$response->addHeader('Access-Control-Allow-Origin', 'https://app.example.com');
$response->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
$response->addHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Api-Key');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
Документирование: OpenAPI / Swagger
API без документации — это API только для тех, кто его написал. Описание эндпоинтов в формате OpenAPI 3.0 создаётся вручную или генерируется из аннотаций (через библиотеки типа zircote/swagger-php). Swagger UI разворачивается как статичная страница в /local/swagger/.
Ограничение запросов (Rate Limiting)
Счётчик запросов на основе Redis или через b_option (для малой нагрузки):
$key = 'api_ratelimit_' . md5($apiKey);
$count = (int)\Bitrix\Main\Data\Cache::createInstance()->get($key);
if ($count > 1000) { // 1000 запросов в час
http_response_code(429);
exit(json_encode(['error' => 'Rate limit exceeded']));
}
// инкремент через Redis или кастомный счётчик
Сроки
| Задача | Срок |
|---|---|
| Базовый REST API (3–5 ресурсов, API-ключ, JSON-ответы) | 1.5–2 недели |
| API с JWT-аутентификацией, правами пользователей, документацией | 3–5 недель |
| Полноценный API с версионированием, rate limiting, тестами, CI | 6–10 недель |
REST API на Битрикс строится из стандартных блоков — контроллеры, ORM, кеш. Сложность не в технологии, а в проектировании: правильные эндпоинты, консистентные форматы ответов, обработка граничных случаев. Плохо спроектированный API становится бременем, которое тянет вниз оба конца интеграции.







