Установка и настройка Swagger Validator

Что? Зачем?

Swagger — популярное решение для документирования API. Он использует OpenAPI Specification. У этого инструмента есть несколько вариантов ведения документации: .json или .yml файлы. Мы документируем всё в .json файлах. Писать документацию это отлично и прекрасно, но было бы замечательно если она будет валидной и рабочей.

Что такое валидатор и как он работает?

Для того, чтобы наша документация была валидной у Swagger есть валидатор. Да, json схему OpenAPI спецификации можно провалидировать спокойно онлайн на нескольких ресурсах (тыц, тыц, тыц), но гораздо удобнее, когда такой инструмент есть здесь и рядом. В документации Swagger в правом нижнем углу есть значок-изображение, который сигнализирует о валидности схемы, которая была разработана.

По-умолчанию, валидация происходит благодаря онлайн валидатору. Он обращается по урлу к нашей документации, валидирует и сообщает ответ в виде изображения. При клике по этому изображению происходит переход на страницу валидатора с дебаг информацией, где отображаются ошибки или сообщение “всё ок”.

Почему не работает онлайн валидатор

В принципе, онлайн валидатора вполне достаточно, если ваша документация открыта в публичном доступе. А если документация в закрытом от внешних глаз доступе онлайн валидатор не поможет. Что же делать и как же быть? Оказывается — всё очень просто. Особенно просто писать о том, что просто, когда всё уже установлено и настроено. Есть пакет на github, который можно установить с помощью докера и всё будет прекрасно.

Попытка установить пакет без использования докера

А что делать если проект не упакован в докер? И тут начинаются танцы с бубном. Сами танцы я пропущу и перейду сразу к бубнам. Для запуска валидатора необходимо установить Apache Maven и java. И, конечно же, выкачать сам пакет:

git clone https://github.com/swagger-api/validator-badge git
cd git
mvn package jetty:run

Последняя команда запускает maven с валидатором на борту. На этом всё — валидатор доступен по ссылке http://localhost:8080/validator?url=<json_schema_url>. В качестве параметра url необходимо передать путь к .json документации. Например, в нашем случае это выглядит вот так http://localhost:8080/validator?url=https://domain.local/swagger/resources/openapi.json

Работает, работает да не работает

Валидатор и вправду работает, если у вас один .json файл без использования $refв схеме. Необходимо обладать сумасшедшим запасом терпения, если у вас большое (5+) количество эндпойнтов с разными response объектами, чтобы хранить их в одном .json файле.

У нас в команде основной файл содержит ссылки на другие подсхемы и при таком подходе валидатор всегда говорит о том, что всё ок — всё валидно даже если в подсхемах есть очевидные ошибки. Вариант решения этой проблемы на поверхности — нужен цельный файл без ссылок на подсхемы.

Генерирование общего файла без $ref

С этим нам помог инструмент swagger-merger. Здесь всё просто: устанавливаете пакет и выполняете команду

./node_modules/swagger-merger/bin/swagger-merger.js -i public/swagger/resources/openapi.json -o public/swagger/resources/combinedSchema.json

Мы для удобства добавили скрипт в composer.json

"scripts": { "swagger-merger": [ "./node_modules/swagger-merger/bin/swagger-merger.js -i public/swagger/resources/openapi.json -o public/swagger/resources/combinedSchema.json" ] }, "scripts-descriptions": { "swagger-merger": "Merge openapi references to one combined schema."
},

и всё сводится к трём словам в командной строке composer swagger-merger. После создания файла указываем ссылку на него валидатору и теперь валидатор корректно валидирует нашу схему.

Отображение статуса валидации

Подход, который я описал выше удобен для локальной разработки когда есть возможность обратиться к валидатору, передав ему ссылку на документацию. Но ведь гораздо удобнее чтобы результат работы валидатора отображался сразу в схеме. И тут ещё немного работы осталось.

Нам необходимо в скрипте инициализации Swagger на странице документации указать URL валидатора:

<script> window.onload = function() { // Begin Swagger UI call region const ui = SwaggerUIBundle({ ... validatorUrl: "http://api_doc_url/swagger/badge" }); // End Swagger UI call region window.ui = ui; }; </script>

Решили указать не тот URL, на котором запущен сам валидатор, а наш кастомный. Для обработки запроса к нему есть 2 пути: через nginx и обычными средствами php.

Валидатор нужен не только в локальном окружении разработчика, но и в тестовом где-то на далёком и доступном всем тестировщикам сервере. Для этого мы развернули его на отдельном выделенном сервере и теперь вместо http://localhost:8080/validator он доступен по нашему URL сервера — http://validator.url/validator

Путь первый (через nginx) выглядит вот так: в настройках nginx нашей документации добавили директиву location, которая перехватывает запрос и отправляет нашу .json схему валидатору

location ~ ^/swagger/badge(?<debug>/debug)? { limit_except GET { deny all; } set $proxy_pass http://validator.url/validator$debug; proxy_buffering off; proxy_pass $proxy_pass; proxy_method POST; proxy_set_header 'Content-Type' 'application/json'; access_by_lua_block { ngx.req.read_body(); local fd = io.open(ngx.var.root .. "/public/swagger/resources/combinedSchema.json", "r") if not fd then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end schema = fd:read("*a") if not schema then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end ngx.req.set_body_data(schema) } }

Путь второй (через php) выглядит как обычная реализация запрос-контроллер-экшн_метод. В запросе к контроллеру GET-параметром придёт url с нашей json схемой и наша задача передать её содержимое валидатору. В ответе с сервера валидатора вернётся изображение-статус валидации. Приблизительно код получается такой:

$schemaUrl = (string) $request->query->get('url'); $schemaRequest = $this->httpClient->request('GET', $schemaUrl);
$schema = $schemaRequest->getContent(); $request = $this->httpClient->request('POST', 'http://validator.url/validator', [ 'body' => $schema, 'headers' => [ 'Content-Type' => 'application/json' ] ]
); $result = $request->getContent(); return new JsonResponse( utf8_encode($result), Response::HTTP_OK, ['Content-Type' => 'image/png']
);

Для получения дебаг-информации код будет приблизительно следующим:

$schemaUrl = (string) $request->query->get('url');
$schemaRequest = $this->httpClient->request('GET', $schemaUrl);
$schema = $schemaRequest->getContent(); $request = $this->httpClient->request('POST', 'http://validator.url/validator/debug', [ 'body' => $schema, 'headers' => [ 'Content-Type' => 'application/json' ] ]
); $result = $request->getContent(); return new JsonResponse( \json_decode($result, true, 512, \JSON_THROW_ON_ERROR), Response::HTTP_OK
);

На этом всё. Открывая страницу нашей документации в правом нижнем углу должно отображаться изображение со статусом валидации.

Надежды на светлое будущее

Этот тернистый путь мы проделали сами и надеемся, что вам он поможет сэкономить время, деньги и терпение.

Настройкой сервера валидатора и написанием кода занимался не я один, а с помощью Михаила Даниленко и Ольги Демчишиной.

Читайте так же:

  • Продажа контента единовременная покупка контента estПродажа контента единовременная покупка контента est Кто отвечает за создание наиболее ценного контента вашей компании? Ваша маркетинговая команда? Агентство? - Ты? Как насчет ваших клиентов? Клиенты круглосуточно генерируют качественный контент для компаний по всему миру. По моему опыту, однако, немногие компании поняли этот факт, не […]
  • Компактный флагман Asus ZenFone 8 стал лучше снимать и получил новые функцииКомпактный флагман Asus ZenFone 8 стал лучше снимать и получил новые функции Компания Asus выпустила первое обновление для своего компактного флагманского смартфона ZenFone 8, которое проходит под номером WW 30.11.51.41. После обновление у пользователей появилась возможность выбирать «приоритетные контакты». Вызовы с которых всегда будут слышны. Даже при […]
  • Кодекс летописца, или Ода к телеметрииКодекс летописца, или Ода к телеметрии Допустим, ко группе инженеров снизошла задача разработать систему управления чем-нибудь достаточно сложным. Теоретик заточил зубы и приступил к граниту — строит модели объекта и системы управления. Комплексники копают руду компоновки, вопросов климатики, вибрации и спецтребований, кто-то […]
  • Таргетированная реклама в социальных сетяхТаргетированная реклама в социальных сетях Описание После обучения вы сможете самостоятельно с нуля настраивать эффективную таргетированную рекламу в ВКонтакте, Facebook. Инстаграм и MyTarget. За 16 занятий вы поймете, как не сливать бюджет. Получать результат в виде продаж и конверсий и привлекать качественный трафик на […]