API 1С «на стероидах»: как «подружить» HTTP-сервисы со Swagger

от автора

Мой коллега Денис рассказывает о практическом способе интеграции HTTP-сервисов 1С со Swagger через расширение swagger-1С, позволяющим автоматически генерировать живую интерактивную документацию API без ручного описания JSON-схем.

Введение. Зачем это вообще нужно (и почему все статьи — не про то)

Реальная ситуация из прошлого. В чат с интегратором падает сообщение: «А какой формат даты вы принимаете? Структура JSON есть? Можно пример?» И вы в десятый раз скриншотите свою тестовую обработку или скидываете ссылку на устаревший Word-файлик, который уже никто не обновлял.

В этот момент хочется одного, чтобы внешний мир просто понимал ваше API без ежеминутных уточнений. Чтобы разработчик на другой стороне открыл браузер и увидел: вот методы, вот параметры, вот примеры ответов. И чтобы эта документация всегда соответствовала реальности, потому что она является частью кода.

В мире за пределами 1С такая проблема решена давно и элегантно. Там есть Swagger (он же OpenAPI) — стандарт описания REST API, который понимают все: от фронтендеров до тестировщиков и генераторов клиентского кода.

В 1С же с этим — беда. Из коробки — ничего. Типовые статьи в интернете либо предлагают с нуля писать JSON-схемы руками (спойлер: никто не будет), либо ограничиваются абстрактными «создайте HTTP-сервис и опишите его в комментариях», умалчивая о граблях, на которых вы гарантированно споткнетесь.

А грабли эти увесистые. Например, тот самый CORS, который заставит вас проклясть тот день, когда вы решили подружить браузер с 1С. Или SetHandler 1С-application, молча сбрасывающий ваши заголовки. Или несоответствие типов, когда Swagger показывает одно, а 1С ждет совсем другое.

В этой статье будет инструкция для тех, кто устал читать консоли запросов вслух заказчику. Мы разберем:

  • один из лучших подходов к внедрению Swagger в 1С;

  • примеры с кодом и комментариями, пройдем по живому примеру HTTP-сервиса;

  • и покажу некоторые «грабли», с которыми я столкнулся.

Поехали.

Раздел 1: что такое Swagger/OpenAPI и зачем он 1С-нику.

1.1. Немного теории

Swagger — это целая экосистема инструментов, в центре которой лежит спецификация OpenAPI Specification (OAS).

OpenAPI — это, если можно так сказать, технический паспорт, где на понятном (и человеку, и машине) языке описано:

  • какие URL (методы) у нашего HTTP сервиса;

  • какие параметры можно передать (и где — в заголовке, в строке запроса или в теле);

  • какой формат данных (JSON, XML) он понимает;

  • что он вернет в случае успеха, а что — при ошибке.

Этот «паспорт» можно написать вручную в формате JSON или YAML, а можно сгенерировать автоматически из кода. И вот здесь начинается магия.

На основе этого JSON-файла другие инструменты (например, Swagger UI) строят интерактивную веб-страницу.

Необходимо учесть, что наш Swagger поддерживает несколько интерфейсов (ReDoc, Scalar, Stoplight и RapiDoc). Об этом можно прочитать здесь.

Важно: столкнулся с проблемой при отображении сервиса в браузере, а именно непонятными ошибками, из-за которых описание в браузере вообще не генерировалось. Выход (в моем случае) в адресной строке указал интерфейс RapiDoc (http://<Адрес_опубликованной_базы>/hs/swagger/index.html?ui=RapiDoc ), и все «взлетело».

Мы для примеров будем использовать RapiDoc, и наша веб-страница будет выглядеть примерно так:

На этой странице любой желающий может:

  1. Увидеть полный список доступных методов API (на левой панели).

  2. Прочитать, что каждый метод делает, какие параметры принимает и что отдает.

  3. Тут же, в браузере, отправить тестовый запрос и увидеть реальный ответ от сервера.

Просто открыл браузер и работаешь.

1.2. Три железобетонных аргумента для внедрения.

  1. Стандартизация API. Все ваши методы и структуры данных описаны в едином, общепринятом формате. Интегратору не нужно вникать в «фирменный» стиль 1С. Он просто читает документацию так же, как читает ее для любого современного REST API.

  2. Автодокументирование и «единство кода и правды». Это ключевой момент. Если вы правильно организуете процесс, Swagger-спецификация будет генерироваться автоматически на основе вашего кода. Вы меняете логику — документация обновляется сама при следующей сборке. Забудьте про «документацию в Word».

  3. Упрощение тестирования и интеграции. Внешние системы и разработчики могут начать работать с вашим API немедленно, не отвлекая вас вопросами. Это экономит часы переписок и нервов с обеих сторон. Плюс вы сами можете использовать Swagger UI для быстрых тестов своей разработки.

1.3. Почему в 1С с этим сложно.

Платформа не умеет генерировать спецификацию по вашим HTTP-сервисам. Все, что мы будем делать дальше, — это описывать наши HTTP-сервисы, красиво и удобно.

Что потребуется от вас:

  • только установка расширений в конфигурацию;

  • иногда небольшие настройки веб-сервера (в случае каких-то трудностей).

И это нормально. Платформа 1С развивается в сторону веб-технологий, но пока что многие вещи приходится делать руками.

Раздел 2: один подход, который реально работает.

Swagger 1С – это расширение, которое ставится в конфигурацию, само подхватывает твои HTTP-сервисы через специальные общие модули-описатели и прямо в рантайме отдает и Swagger UI, и спецификацию.

Три причины использования:

  1. Живая документация. Расширение само генерирует спецификацию на лету — не надо руками запускать скрипты при каждом чихе.

  2. Минимум телодвижений. Установил расширение, включил галку публикации, создал модуль-описание по шаблону — всё работает.

  3. Проверка параметров из коробки. Расширение умеет само проверять входящие данные на соответствие.

Единственный момент — придется немного подружить это хозяйство с веб-сервером.

Раздел 3: Установка и настройка расширения.

3.1. Где брать.

Репозиторий проекта

3.2. Установка.

Заходим в конфигуратор целевой базы.
Создаем новое расширение (имя любое, например Swagger).
Через меню «Конфигурация -> Загрузить конфигурацию из файла» и выбираем наш файл расширения. Обновляем конфигурацию базы.

3.3. Публикация на веб-сервере.

Тут важный момент, про который забывают в половине инструкций.
После установки расширения нужно переопубликовать базу на веб-сервере и обязательно поставить галку: «Публиковать HTTP сервисы расширений по умолчанию».

Без этой галки ваше расширение будет лежать мертвым грузом, и по адресу /hs/swagger/index.html будет 404.

После публикации перезапустить веб-сервер. IIS, Apache — не важно. Просто рестарт, чтобы подхватились все настройки.

3.4. Проверка, что всё ожило.

Открываем браузер и идем по адресу:
http://<Адрес_опубликованной_базы>/hs/swagger/index.html*

* — добавляется имя интерфейса, например: ?ui=RapiDoc

Если видим картинку примерно такой, как на рисунке, то у вас все заработало.

Раздел 4: описываем первый HTTP-сервис.

4.1. Что хочет расширение.

Расширение ищет описания HTTP-сервисов в общих модулях, имена которых строятся по шаблону:
«<Имя_HTTP_сервиса>Описание».

То есть если ваш HTTP-сервис называется ОбменДанными, то общий модуль-описание должен называться ОбменДаннымиОписание. Регистр важен.

4.2. Живой пример: сервис остатков.

Для примера возьмем типовую задачу — HTTP-сервис, который отдает остатки по складу.

Имя HTTP-сервиса в метаданных: ОстаткиСклада.
Шаблон URL: /stocks.
Метод: GET.
Параметры запроса: storageCode (код склада, обязательный), productFilter (фильтр по товарам — массив ID, опционально).
Ответ: массив объектов с полями productId, quantity, price.

4.3. Создаем модуль-описание.

Создаем общий модуль с именем ОстаткиСкладаОписание.

В этом модуле нам нужно описать все методы нашего HTTP-сервиса. Три обязательные функции:

Вот как будет выглядеть описание для нашего GET-метода в функции ПолучитьОписаниеHTTPСервиса():

// Возвращает основной массив описаний HTTP-Сервиса// // Возвращаемое значение://  Массив - Список сформированного описания методов HTTP-сервиса. См. https://zerobig.github.io/swagger-1c/docs/getting-started/methods_func_style //Функция ПолучитьОписаниеHTTPСервиса() ЭкспортМетоды = Swag_Описание.Метод("ОстаткиСкладаGET").ОписаниеМетода("Остатки товаров на складах").ДетальноеОписаниеМетода(НСтр("ru = 'Получение данных по остаткам на складах.'"))  .ПараметрURL("storageCode").ОписаниеПараметра("Код склада, например ""0897""").Тело().ТипТела("application/json").СхемаТела("ОстаткиСкладаGET").Ответ(200).ОписаниеОтвета("Success").ТипОтвета("application/json").СхемаОтвета("ОстаткиСклада_Ответ").Сформировать();Возврат Методы;КонецФункции

А вот так в функции ПолучитьОбъектыHTTPСервиса():

// Возвращает массив объектов описания HTTP-Сервиса// // Возвращаемое значение://  Массив - Список сформированных объектов описания. См. https://zerobig.github.io/swagger-1c/docs/getting-started/objects_func_style//Функция ПолучитьОбъектыHTTPСервиса() ЭкспортОбъекты = Новый Массив;Объекты = Swag_Описание.Объект("ОстаткиСкладаGET") // Описание объекта.Свойство("productFilter").ОписаниеСвойства("Код номенклатуры через запятую").ТипЗначения("array").Схема("ТоварыОтбор")  .Объект("ТоварыОтбор").Свойство("id").ОписаниеСвойства("Код номенклатуры").ТипЗначения("string").Пример("0098778,0098777,0066778,0098668").Объект("ОстаткиСклада_Ответ") .Свойство("id").ОписаниеСвойства("Код номенлатуры").ТипЗначения("string").Пример("202140") .Свойство("name").ОписаниеСвойства("Наименование номенлатуры").ТипЗначения("string").Пример("Мыло детское 100гр") .Свойство("quantity").ОписаниеСвойства("Количество").ТипЗначения("integer").Пример(456) .Свойство("price").ОписаниеСвойства("Цена").ТипЗначения("string").Пример("541,5") .Сформировать();ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Объекты, Swag_ОбщиеОписанияПереопределяемый.ОбъектErrors422());ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Объекты, Swag_ОбщиеОписанияПереопределяемый.ОбъектErrors404());Возврат Объекты;КонецФункции

4.4. А где же сам код?

Важный момент: модуль-описание не содержит исполняемого кода. В нем живут только описания сервиса. Сам обработчик как был в модуле HTTP-сервиса, там и остается. Расширение просто читает наши функции и превращает их в спецификацию.

Но если мы хотим использовать встроенную проверку параметров (а мы хотим), то в коде обработчика надо добавить вызов метода ПроверитьПараметры из расширения.

В модуле HTTP-сервиса ОстаткиСклада обработчик будет выглядеть примерно так:

функция stocksGET (Запрос)// Проверяем входящие параметры по описанию из модуля ОстаткиСкладаОписаниеРезультатПроверки = Swag_ОбработкаНТТР.ПроверитьПараметры("ОстаткиСклада",    // Имя НТТР-сервиса"GET",    // Имя метода (должно совпадать с описанием)Запрос    // Сам запрос);Если Не ПустаяСтрока(РезультатПроверки) ТогдаВозврат Swag_ОбработкаНТТР.ПолучитьОтветОшибки(РезультатПроверки, Истина);КонецЕсли;// --- здесь основная логика получения остатков ---МассивОстатков = МодульОбработкиНТТРСервисов.ПолучитьОстатки(Запрос.Параметры["storageCode"]);Ответ = Новый НТТРСервисОтвет(200);Ответ.УстановитьТелоИзСтроки(МассивОстатков);// Проверяем ответ на соответствие описаниюВозврат Swag_ОбработкаНТТР.ПроверитьОтвет("ОстаткиСклада","GET",Ответ);КонецФункции    

Этот код делает две вещи:

  1. До выполнения логики проверяет, все ли обязательные параметры пришли и правильного ли они типа.

  2. После формирования ответа проверяет, соответствует ли структура данных тому, что мы обещали в описании.

Если что-то не так, расширение само вернет человекочитаемую ошибку. Красота.

Раздел 5: проверка результата.

После того, как модуль-описание создан и код обработчика дописан:

  1. Обновляем конфигурацию базы.

  2. Открываем браузер по адресу http://<сервер>/<база>/hs/swagger/index.html.

  3. Если всё сделано правильно, видим наш метод GET /stocks с полным описанием параметров и структур ответов.

4. Тыкаем Try, вводим код склада, жмем Execute и получаем реальный ответ от сервера прямо в браузере.

Некоторое описание на скриншотах для примера:

Заключение

Мы прошли путь от полного отсутствия документации до работающего Swagger UI, который:

  • автоматически генерируется;

  • проверяет входящие параметры и ответы;

  • позволяет интеграторам самим тестировать методы без нашего участия;

  • не требует танцев с бубном при каждом изменении API.

Пришлось:

  • поставить расширение;

  • создать модули-описания для каждого HTTP-сервиса;

  • приучить себя писать код описания сервисов определенным образом.

Но, поверьте моему опыту, когда в следующий раз интегратор вместо «а скиньте пример» просто откроет Swagger и сам всё увидит, вы скажете себе спасибо.

P.S. Весь код описания сервисов написан исключительно на тестовой базе для тестирования. Все исходники расширения и примеры кода из статьи можно найти в репозитории zerobig/swagger-1c на GitHub.

ссылка на оригинал статьи https://habr.com/ru/articles/1024666/