В прошлой части мы разобрали кто делает запрос и имеет ли право — аутентификацию и авторизацию.
Теперь логичный следующий слой: что именно ваш сервер отдаёт наружу и как внешний мир будет с этим жить годами. Это и есть API‑разработка: договоры, форматы, версии, ошибки, стабильность.
В этой части разберём:
- как в Laravel строится REST API “по‑взрослому” через контроллеры + API Resources,
- как в Bitrix Framework делать кастомные API endpoints через D7‑роутинг +
\Bitrix\Main\Engine\Controller, - чем отличается обработка Request/Response в обоих стеках,
- и как подходить к версионированию API, чтобы проект не умер на версии “v1 навсегда”.
REST API: “контракты”, а не просто JSON
Что обычно забывают Junior’ы
REST API — это не “в PHP вернуть массив, и пусть будет JSON”. Это набор договорённостей:
- URL и методы:
GET /posts,POST /posts,GET /posts/{id}… - коды статусов: 200/201/204/400/401/403/404/422/500 — это часть протокола,
- формат ошибок: предсказуемый и одинаковый во всех эндпоинтах,
- формат данных: что считается публичным, какие поля скрываем, как отдаём связи,
- эволюция: вы сможете менять API без “сломать всех клиентов”.
Laravel: REST API как “путь по умолчанию”
Маршруты API: routes/api.php и Route::apiResource
Типовой старт:
use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;
Route::prefix('v1')->group(function () {
Route::apiResource('posts', PostController::class);
});
apiResource сразу задаёт “дисциплину”:
GET /api/v1/posts→indexPOST /api/v1/posts→storeGET /api/v1/posts/{post}→showPUT/PATCH /api/v1/posts/{post}→updateDELETE /api/v1/posts/{post}→destroy
API Resources: контроль над форматом ответа
Главная проблема API в PHP‑проектах — “случайная публичность”: вы отдали клиенту половину таблицы, а потом не можете убрать поле, потому что его уже используют.
В Laravel это закрывается API Resources:
php artisan make:resource PostResource
Пример ресурса:
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
final class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'body' => $this->body,
'published_at' => optional($this->published_at)?->toIso8601String(),
'author' => UserResource::make($this->whenLoaded('author')),
];
}
}
И контроллер:
use App\Http\Resources\PostResource;
use App\Models\Post;
public function show(Post $post): PostResource
{
$post->load('author');
return PostResource::make($post);
}
Ошибки как часть API
В Laravel у вас есть стандартный “протокол” ошибок:
- валидация обычно возвращает 422,
abort(404)даёт 404,AuthorizationException— 403,AuthenticationException— 401.
Если вы не ломаете стандарт — клиентам проще.
Bitrix: REST “как архитектурное решение”, а не “как магия ядра”
Важно разделить две вещи:
- Сделать свой API внутри Bitrix‑проекта (кастомные endpoints).
- Интегрироваться с Bitrix24 через REST API (когда Bitrix — внешняя платформа).
В этой статье мы фокусируемся на первом — потому что это ближе к “Laravel‑стилю” построения API сервера.
D7‑роутинг + \Bitrix\Main\Engine\Controller = ваш “API‑каркас”
Bitrix Framework умеет роутинг (модуль main), маршруты можно хранить в /local/routes/*.php, а ответы удобно отдавать через D7‑контроллеры.
Концептуально это похоже на Laravel:
- есть маршруты,
- есть контроллеры и действия,
- есть “аналог middleware” — Action Filters,
- есть “стандартный JSON” —
Engine\Response\AjaxJson/Response\Json.
Пример: зарегистрировать API‑маршруты
/bitrix/.settings.php и завести файл с маршрутами.Упрощённый пример local/routes/api.php:
use Bitrix\Main\Routing\RoutingConfigurator;
use My\Api\Infrastructure\Controller\Post;
return static function (RoutingConfigurator $routes) {
$routes
->prefix('api/v1')
->name('api.v1.posts')
->group(static function (RoutingConfigurator $routes) {
$routes->get('posts/', [Post::class, 'list'])->name('list');
$routes->get('posts/{id}/', [Post::class, 'get'])->name('get');
$routes->post('posts/', [Post::class, 'add'])->name('add');
});
};
А внутри контроллера (\Bitrix\Main\Engine\Controller) методы будут называться listAction, getAction, addAction и т.д.
“REST API Bitrix” как интеграционный слой
Если ваша задача — интеграция с Bitrix24 (CRM, задачи, чаты и т.п.), то обычно вы не “поднимаете endpoint внутри своего сайта”, а вызываете методы Bitrix24 REST API со своего сервера.
В проектах часто одновременно есть:
- внутренний API вашего приложения (Laravel/Bitrix) для фронта,
- внешняя интеграция через Bitrix24 REST API.
Обработка запросов: Request/Response как “механика чистоты”
Почему это важно
Один и тот же endpoint можно сделать:
- “как попало” — и он будет работать ровно до первого сложного кейса,
- “как слой” — и он масштабируется, тестируется и не превращается в свалку.
И тут request/response — это не мелочь, а фундамент:
- где валидируем,
- где нормализуем,
- где авторизуем,
- где формируем ошибки,
- где задаём формат ответа.
Laravel: Request, валидация, ответы и исключения
Request: один объект вместо $_GET/$_POST
use Illuminate\Http\Request;
public function index(Request $request)
{
$page = (int) $request->query('page', 1);
$q = (string) $request->query('q', '');
// ...
}
Laravel поощряет выносить валидацию в слой “на входе”:
public function store(Request $request)
{
$data = $request->validate([
'title' => ['required', 'string', 'max:200'],
'body' => ['required', 'string'],
]);
// ...
}
Для API‑проектов это особенно важно: вы не хотите, чтобы внутри бизнес‑логики постоянно жили if (!isset(...)).
Responses: явный JSON и коды статусов
return response()->json([
'ok' => true,
'data' => $payload,
], 200);
Старайтесь всегда возвращать:
- корректный статус,
- корректный
Content-Type, - единый формат для успеха и ошибок.
Bitrix: HttpRequest/HttpResponse, контекст и JSON‑ответы контроллеров
Request через контекст
В Bitrix Framework запрос берут из контекста (вместо прямых глобальных переменных):
use Bitrix\Main\Context;
$request = Context::getCurrent()->getRequest();
$q = $request->getQuery('q');
$title = $request->getPost('title');
Из полезного, что часто нужно в API‑обработчиках:
$request->getRequestMethod()— метод,$request->isAjaxRequest()— AJAX,$request->isHttps()— HTTPS,$request->getRequestUri()— полный URI.
Response: два “типовых” пути
- Вернуть массив/скаляр из action — контроллер сам оформит JSON (через
AjaxJson). - Вернуть “явный” JSON‑ответ — через
\Bitrix\Main\Engine\Response\Json.
Пример явного JSON:
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Engine\Response\Json;
final class Post extends Controller
{
public function statusAction(): Json
{
return new Json(['ok' => true]);
}
}
Action Filters: Bitrix‑аналог middleware
В Bitrix роль middleware играют Action Filters (префильтры/постфильтры): проверка метода, аутентификация, CSRF, scope и т.д.
Пример: ограничить методами и требовать аутентификацию:
use Bitrix\Main\Engine\ActionFilter\Attribute\Rule\Prefilters;
use Bitrix\Main\Engine\ActionFilter\Authentication;
use Bitrix\Main\Engine\ActionFilter\HttpMethod;
final class Post extends \Bitrix\Main\Engine\Controller
{
#[Prefilters([
new Authentication(),
new HttpMethod([HttpMethod::METHOD_GET]),
])]
public function listAction(): array
{
return ['items' => []];
}
}
Ошибки и результат: Result/ErrorCollection
Если вы хотите не “падать исключением на первом же поле”, а отдавать набор ошибок (как при валидации), в Bitrix есть стандартная конструкция \Bitrix\Main\Result:
use Bitrix\Main\Error;
use Bitrix\Main\Result;
$result = new Result();
if ($title === '') {
$result->addError(new Error('Поле title обязательно', 'TITLE_REQUIRED'));
}
if (!$result->isSuccess()) {
return [
'ok' => false,
'errors' => $result->getErrorMessages(),
];
}
Версионирование API: как не застрять в “v1 навсегда”
Версионирование — это не “папка v2”. Это стратегия:
- как добавлять поля без breaking changes,
- как менять форматы,
- как выводить из эксплуатации старые клиенты,
- как мигрировать фронт/мобильные приложения.
Лучше иметь “скучный” план версий, чем “умный” хаос.
Laravel: версионирование через префиксы и группы
Самый понятный вариант — URL‑версия:
use Illuminate\Support\Facades\Route;
Route::prefix('v1')->group(function () {
// v1 endpoints
});
Route::prefix('v2')->group(function () {
// v2 endpoints
});
Так вы можете:
- параллельно поддерживать v1 и v2,
- постепенно переводить клиентов,
- не ломать старые интеграции.
А вот что важно дисциплинировать:
- не меняйте смысл существующих полей в рамках версии,
- новые поля добавляйте так, чтобы старый клиент мог их игнорировать,
- breaking changes — только в новой версии.
API Resources как инструмент “мягких” изменений
Частая техника: разные Resource‑классы для v1/v2 (или один Resource с условием по версии).
Пример по‑простому (разные классы):
PostResourceV1PostResourceV2(добавили поле/переименовали/изменили структуру)
Плюс: меньше магии. Минус: больше файлов.
Bitrix: версии как часть маршрутов и “границ пространства URL”
В Bitrix для внутреннего API обычно проще и безопаснее всего тоже идти по URL‑версиям:
/api/v1/.../api/v2/...
Технически вы делаете это:
- через
prefix('api/v1')в файле маршрутов, - через отдельный файл маршрутов (например,
api_v1.php,api_v2.php), - или через разные контроллеры/модули.
Если у вас есть
/catalog/ и /api/ — разделяйте пространства URL максимально явно.Типовые ошибки API‑проектов (и как их не повторить)
Кейс А “Модель = API”
Если вы отдаёте модель как есть (в Laravel) или “массив из базы как есть” (в Bitrix), вы:
- раскрываете лишние поля,
- ломаете клиентов при любом изменении,
- теряете контроль над контрактом.
Кейс B “Ошибки в каждом endpoint свои”
Клиент начинает писать “парсер ошибок” на 10 форматов.
Кейс C “Версия одна и навсегда”
В реальности вы всё равно измените API. Вопрос только — с контролем или без.
Сравнительная таблица: API‑разработка
Шкала (как и раньше): от -2 до +2.
| Критерий | Laravel (баллы) | Битрикс (баллы) | Комментарий |
|---|---|---|---|
| “API как стандартный сценарий” | +2 | +1 | Laravel изначально “про приложение”. В Bitrix API есть, но качество зависит от выбранной архитектуры (D7‑контроллеры vs legacy‑обработчики). |
| Трансформация данных (контракт ответа) | +2 | 0 | Laravel: API Resources. В Bitrix это обычно проектный слой, который нужно дисциплинировать. |
| Единый подход к ошибкам | +2 | +1 | В Laravel многое приходит стандартом (422/403/401). В Bitrix есть Result/ErrorCollection, но формат ответа вы фиксируете сами. |
| “Middleware/Filters” как единый механизм правил | +2 | +1 | Laravel: middleware. Bitrix: action filters (мощно, но нужно привыкнуть и использовать системно). |
| Версионирование и эволюция API | +2 | +1 | В обоих можно делать URL‑версии, но в Laravel это чаще встречается и проще стандартизировать. |
| Интеграции с внешними системами | +1 | +2 | Laravel интегрируется через пакеты/HTTP‑клиенты. У Bitrix часто сильная сторона — экосистема интеграций, включая Bitrix24 REST API/маркетплейс. |
| Итого за статью | +11 | +6 | |
| Общий счёт (накопительный) | +77 | +43 | Счёт накапливается по мере выхода статей. |
Laravel силён тем, что API‑путь максимально прямой:
routes/api.php+apiResource,- API Resources как контроль контракта,
- предсказуемые статусы и ошибки,
- версионирование через группы маршрутов.
Bitrix силён тем, что вы можете построить “настоящий API” внутри платформы — через D7‑роутинг, контроллеры и action filters — и жить в единой экосистеме сайта/админки/модулей. Цена — договорённости команды: формат ответа, ошибки, стандарты контроллеров, разделение /api и сайта.
В следующей части перейдём к теме, где API почти всегда встречается с нагрузкой: события и очереди (Laravel Events/Queue vs Bitrix EventManager и агенты/фоновые задачи).
Один и тот же “Posts API” в двух стеках
Цель: почувствовать, что API — это соглашения, а не “вернуть JSON”.
Задание для Laravel
Соберите v1 API:
GET /api/v1/posts— список постов (можно заглушки)GET /api/v1/posts/{id}— один постPOST /api/v1/posts— создать пост (валидация:titlerequired, max 200)- Формат ответа — через
PostResource - Ошибки валидации должны возвращаться стандартно (422)
Опорные доки: API Resources, Validation, Responses.
Задание для Битрикса
Соберите v1 API через D7‑роутинг + контроллер:
GET /api/v1/posts/— вернуть JSON со спискомGET /api/v1/posts/{id}/— вернуть JSON одного постаPOST /api/v1/posts/— создать пост (минимальная валидация)- Включите хотя бы один action filter:
HttpMethod(ограничить методы),- и/или
Authentication(защитить создание), - и/или
Csrf(если это вызовы из браузера/JS).
- Договоритесь о формате ошибок (например,
ok: false,errors: [...]) и соблюдайте его везде.
Опорные доки: Роутинг, Контроллеры, Request/Response, Пре- и постфильтры.