Розробка типізованого SDK для API 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Розробка типізованого SDK для API 1С-Бітрікс
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Розробка типізованого SDK для API 1С-Бітрікс

Написання інтеграцій з 1С-Бітрікс без SDK — це постійний copy-paste коду авторизації, ручна серіалізація запитів, рядкові назви методів без автодоповнення. Через півроку проєкт перетворюється на нечитабельний клубок curl_exec() з json_decode(). Типізований SDK вирішує це: кожен метод API — окремий клас або метод з PHPDoc, автодоповнення в IDE, єдина точка конфігурації, вбудована обробка помилок.

Що таке SDK для Бітрікс

SDK у цьому контексті — це PHP-бібліотека, яка інкапсулює роботу з одним з API:

  1. REST API Битрикс24 (хмарний і коробочний) — методи виду crm.lead.add, tasks.task.update.
  2. API 1С-Бітрікс (сайт) — внутрішні класи CIBlockElement, \Bitrix\Sale\Order, D7 ORM.
  3. Webhook API — вхідні та вихідні вебхуки Битрикс24.

Найчастіше SDK розробляється для REST API Битрикс24 — ним користуються зовнішні застосунки та інтеграції.

Структура типізованого REST API SDK

src/
├── Client/
│   ├── BitrixClient.php          # HTTP-клієнт (Guzzle/native curl)
│   ├── TokenStorage.php          # Зберігання OAuth-токенів
│   └── RetryMiddleware.php       # Повторні спроби при 503/rate limit
├── Api/
│   ├── Crm/
│   │   ├── LeadApi.php
│   │   ├── DealApi.php
│   │   ├── ContactApi.php
│   │   └── CompanyApi.php
│   ├── Tasks/
│   │   ├── TaskApi.php
│   │   └── CommentApi.php
│   └── Catalog/
│       ├── ProductApi.php
│       └── PriceApi.php
├── Dto/
│   ├── Crm/
│   │   ├── Lead.php
│   │   ├── LeadCreateRequest.php
│   │   └── LeadListRequest.php
│   └── Common/
│       ├── Pagination.php
│       └── Filter.php
├── Exception/
│   ├── BitrixApiException.php
│   ├── AuthException.php
│   └── RateLimitException.php
└── BitrixSdk.php                 # Точка входу / DI-контейнер

HTTP-клієнт

namespace BitrixSdk\Client;

class BitrixClient
{
    private string $baseUrl;
    private TokenStorage $tokenStorage;
    private \GuzzleHttp\Client $http;

    public function __construct(string $baseUrl, TokenStorage $tokenStorage)
    {
        $this->baseUrl      = rtrim($baseUrl, '/') . '/rest/';
        $this->tokenStorage = $tokenStorage;
        $this->http         = new \GuzzleHttp\Client([
            'timeout'         => 30,
            'connect_timeout' => 10,
        ]);
    }

    public function call(string $method, array $params = []): array
    {
        $token  = $this->tokenStorage->getAccessToken();
        $url    = $this->baseUrl . $method;

        try {
            $response = $this->http->post($url, [
                'json' => array_merge($params, ['auth' => $token]),
            ]);

            $data = json_decode($response->getBody()->getContents(), true);

            if (!empty($data['error'])) {
                $this->handleError($data);
            }

            return $data['result'] ?? $data;

        } catch (\GuzzleHttp\Exception\ClientException $e) {
            $statusCode = $e->getResponse()->getStatusCode();
            if ($statusCode === 401) {
                // Спробувати оновити токен
                $this->tokenStorage->refresh();
                return $this->call($method, $params);
            }
            throw new BitrixApiException("HTTP {$statusCode}: " . $e->getMessage(), $statusCode);
        }
    }

    private function handleError(array $data): void
    {
        $errorCode = $data['error'] ?? 'UNKNOWN';
        $errorDesc = $data['error_description'] ?? '';

        if ($errorCode === 'QUERY_LIMIT_EXCEEDED') {
            // Rate limit — затримка і повтор
            throw new RateLimitException($errorDesc);
        }

        if (in_array($errorCode, ['NO_AUTH_FOUND', 'expired_token', 'invalid_token'])) {
            throw new AuthException($errorDesc);
        }

        throw new BitrixApiException("{$errorCode}: {$errorDesc}");
    }

    /** Пакетний запит — batch */
    public function batch(array $commands): array
    {
        $cmdParams = [];
        foreach ($commands as $key => $command) {
            $cmdParams[$key] = $command->toApiParam();
        }

        $result = $this->call('batch', ['cmd' => $cmdParams]);
        return $result['result'] ?? [];
    }
}

DTO та типізовані методи

Замість роботи з сирими масивами — Data Transfer Objects:

namespace BitrixSdk\Dto\Crm;

class LeadCreateRequest
{
    public string $title;
    public ?string $name        = null;
    public ?string $lastName    = null;
    public ?string $phone       = null;
    public ?string $email       = null;
    public string $sourceId     = 'WEB';
    public ?string $comments    = null;
    public int $responsibleId   = 0;
    /** @var array<string, string> */
    public array $utmFields     = [];

    public function toApiArray(): array
    {
        $fields = [
            'TITLE'     => $this->title,
            'SOURCE_ID' => $this->sourceId,
        ];

        if ($this->name)     $fields['NAME']      = $this->name;
        if ($this->lastName) $fields['LAST_NAME']  = $this->lastName;
        if ($this->comments) $fields['COMMENTS']   = $this->comments;

        if ($this->phone) {
            $fields['PHONE'] = [['VALUE' => $this->phone, 'VALUE_TYPE' => 'WORK']];
        }
        if ($this->email) {
            $fields['EMAIL'] = [['VALUE' => $this->email, 'VALUE_TYPE' => 'WORK']];
        }

        foreach ($this->utmFields as $key => $value) {
            $fields[$key] = $value;
        }

        return $fields;
    }
}

class Lead
{
    public int $id;
    public string $title;
    public ?string $name;
    public ?string $lastName;
    public string $status;
    public float $opportunity;
    public \DateTimeImmutable $dateCreate;

    public static function fromApiArray(array $data): self
    {
        $lead              = new self();
        $lead->id          = (int)$data['ID'];
        $lead->title       = $data['TITLE'];
        $lead->name        = $data['NAME'] ?? null;
        $lead->lastName    = $data['LAST_NAME'] ?? null;
        $lead->status      = $data['STATUS_ID'];
        $lead->opportunity = (float)($data['OPPORTUNITY'] ?? 0);
        $lead->dateCreate  = new \DateTimeImmutable($data['DATE_CREATE']);
        return $lead;
    }
}

API-клас для лідів

namespace BitrixSdk\Api\Crm;

class LeadApi
{
    public function __construct(private BitrixClient $client) {}

    public function add(LeadCreateRequest $request): int
    {
        $result = $this->client->call('crm.lead.add', [
            'fields' => $request->toApiArray(),
        ]);
        return (int)$result;
    }

    public function get(int $id): Lead
    {
        $data = $this->client->call('crm.lead.get', ['id' => $id]);
        return Lead::fromApiArray($data);
    }

    /**
     * @return Lead[]
     */
    public function list(array $filter = [], array $select = [], int $start = 0): array
    {
        $params = ['filter' => $filter, 'start' => $start];
        if ($select) $params['select'] = $select;

        $data = $this->client->call('crm.lead.list', $params);
        return array_map(fn($item) => Lead::fromApiArray($item), $data);
    }

    public function update(int $id, array $fields): bool
    {
        return (bool)$this->client->call('crm.lead.update', [
            'id'     => $id,
            'fields' => $fields,
        ]);
    }
}

Точка входу SDK

namespace BitrixSdk;

class BitrixSdk
{
    private BitrixClient $client;
    private ?Crm\LeadApi $leadApi     = null;
    private ?Crm\DealApi $dealApi     = null;
    private ?Tasks\TaskApi $taskApi   = null;

    public static function create(string $webhookUrl): self
    {
        $sdk         = new self();
        $storage     = new Client\WebhookTokenStorage($webhookUrl);
        $sdk->client = new Client\BitrixClient($webhookUrl, $storage);
        return $sdk;
    }

    public static function createOAuth(string $domain, string $clientId, string $clientSecret, TokenStorage $storage): self
    {
        $sdk         = new self();
        $sdk->client = new Client\BitrixClient("https://{$domain}", $storage);
        return $sdk;
    }

    public function crm(): CrmFacade
    {
        return new CrmFacade($this->client);
    }

    public function tasks(): TasksFacade
    {
        return new TasksFacade($this->client);
    }
}

// Використання
$sdk  = BitrixSdk::create('https://company.bitrix24.ru/rest/1/webhook_token/');
$lead = new LeadCreateRequest();
$lead->title = 'Заявка з сайту';
$lead->name  = 'Іван';
$lead->phone = '+79001234567';
$leadId = $sdk->crm()->leads()->add($lead);

Rate Limiting та черга

Битрикс24 обмежує запити: 2 запити/сек для хмарних порталів. При перевищенні — HTTP 503 з X-RateLimit-Reset. SDK має це обробляти:

class RetryMiddleware
{
    private const MAX_RETRIES   = 3;
    private const RETRY_DELAYS  = [1, 2, 5]; // секунди

    public function handle(callable $next, string $method, array $params): array
    {
        for ($attempt = 0; $attempt <= self::MAX_RETRIES; $attempt++) {
            try {
                return $next($method, $params);
            } catch (RateLimitException $e) {
                if ($attempt === self::MAX_RETRIES) throw $e;
                sleep(self::RETRY_DELAYS[$attempt]);
            }
        }
        throw new BitrixApiException('Max retries exceeded');
    }
}

Для масових операцій (імпорт 10 000 лідів) — використовувати batch-метод Бітрікс (до 50 команд за раз) та чергу (Laravel Queue, RabbitMQ, Redis Queue).

Терміни розробки

Варіант Склад Термін
Базовий SDK CRM-методи, HTTP-клієнт, DTO, обробка помилок 8–12 днів
Розширений + Tasks, каталог, webhooks, rate limiting 14–20 днів
Повний SDK з тестами + PHPUnit тести, CI/CD, packagist-пакет 20–30 днів