Руководство по swagger

Edit me

Swagger UI предоставляет Фреймворк, который читает спецификацию OpenAPI. и создает веб-страницу с интерактивной документацией. В этом руководстве показано, как интегрировать документ спецификации OpenAPI в интерфейс Swagger.

Концептуальный обзор OpenAPI и Swagger можно посмотреть в разделе Знакомство со спецификациями OpenAPI и Swagger. Пошаговое руководство по созданию документа спецификации OpenAPI смотрим в Обзоре руководства OpenAPI 3.0.

Swagger UI — один из самых популярных инструментов для создания интерактивной документации. Swagger UI создает интерактивную консоль API для экспериментов с запросами в реальном времени. Кроме того, Swagger UI (активно управляемый проект с лицензией Apache 2.0) поддерживает последнюю версию спецификации OpenAPI (3.x) и интегрируется с другими инструментами Swagger.

Прежде чем мы углубимся в Swagger, нужно прояснить ключевые термины.

Swagger

Относится к инструментам API, связанным со спецификацией OpenAPI. Некоторыми из этих инструментов являются Swagger Editor, Swagger UI, Swagger Codegen, SwaggerHub и другие. Всеми инструментами управляет компания Smartbear. Для получения дополнительной информации см. Инструменты Swagger. «Swagger» являлся изначально оригинальным названием спецификации OpenAPI, но позже имя было изменено на OpenAPI, чтобы усилить открытый, не лицензионный характер стандарта. Люди иногда ссылаются на оба имени взаимозаменяемо (особенно на старых веб-страницах), но «OpenAPI» — это то, как следует обращаться к спецификации. Дополнительные сведения о разнице между OpenAPI и Swagger см. В разделе «В чем разница между Swagger и OpenAPI?».

OpenAPI

Официальное название спецификации OpenAPI. Спецификация OpenAPI предоставляет набор свойств, которые можно использовать для описания REST API. Рабочий, валидный документ можно использовать для создания интерактивной документации, создания клиентских SDK, запуска модульных тестов и многого другого. Подробности спецификации можно изучить на GitHub по адресу https://github.com/OAI/OpenAPI-Specification. В рамках инициативы Open API с Linux Foundation спецификация OpenAPI направлена ​​на то, чтобы быть независимой от производителя (многие компании участвуют в ее разработке).

Swagger Editor

Онлайн-редактор, который проверяет документацию OpenAPI на соответствие правилам спецификации OpenAPI. Редактор Swagger помечает ошибки и дает советы по форматированию.

Swagger UI

Веб-фрэймворк (на GitHub), который анализирует документ в спецификации OpenAPI и создает веб-страницу интерактивной документации. Swagger UI — это инструмент, который превращает спецификацию в подобный Petstore-сайт.

Swagger Codegen

Генерирует код SDK для множества различных платформ (таких как Java, JavaScript, Scala, Python, PHP, Ruby, Scala и другие). Код SDK помогает разработчикам интегрировать API на конкретной платформе и обеспечивает более надежные реализации, которые могут включать в себя больше масштабирования, многопоточности и т.д.. В общем, SDK — это наборы инструментов для реализации запросов, сделанных с помощью API. Swagger Codegen генерирует клиентские SDK практически на каждом языке программирования. См. Swagger Codegen для получения дополнительной информации. Смотрите также SDK и примеры приложений.

Знакомство со Swagger при помощи Petstore

Чтобы лучше понять интерфейс Swagger, давайте рассмотрим пример Swagger Petstore. В примере Petstore сайт генерируется с помощью Swagger UI.

Petstore

Конечные точки сгруппированы следующим образом:

  • pet
  • store
  • user

Авторизация запроса

Прежде чем делать какие-либо запросы, нужна авторизация. Нажимаем кнопку Authorize и заполняем информацию, требуемую в окне «Авторизация», изображенном ниже:

Authorize

Пример Petstore имеет модель безопасности OAuth 2.0. Код авторизации только для демонстрационных целей. Нет никакой реальной логики авторизации этих запросов, поэтому просто закрываем окно Авторизации.

Создание запроса

Теперь создадим запрос:

  • Разворачиваем конечную точку POST Pet
  • Нажимаем кнопку Try it out

Try it out

После того, как мы нажмем кнопку Try it out, значение примера в поле «Тело запроса» станет редактируемым.

  • В поле «Example Value» изменяем первое значение id на случайное целое число, например 193844. Также значение второго name на другое (имя вашего питомца).
  • Нажимаем Execute.

Execute

Выполнение примера запроса Petstore

Пользовательский интерфейс Swagger отправляет запрос и показывает отправленный curl. Раздел Ответы показывает ответ. (Если выбрать JSON вместо XML в раскрывающемся списке «Response content type», формат ответа будет показан в формате JSON.)

Response

Проверка создания питомца

  1. Разворачиваем точку GET /pet/{petId}
  2. Нажимаем кнопку Try it out
  3. Вводим ID питомца, который использовали в предыдущей операции. (Если забыли ID, посмотрите на конечную точку POST Pet, чтобы проверить значение.)
  4. Нажимаем Execute . В ответе мы должны увидеть имя нашего питомца.

Примеры сайтов с документаций по Swagger UI

Прежде чем мы перейдем к другому API с этим пособием по Swagger (кроме демонстрации Petstore), посмотрим на другие реализации Swagger:

  • Reverb
  • VocaDB
  • Watson Developer Cloud
  • The Movie Database API
  • Zomato API

Некоторые из этих сайтов выглядят одинаково, но другие, такие как The Movie Database API и Zomato, были легко интегрированы в остальную часть их сайта документации.

Глядя на примеры, можно заметить краткость документации в реализации Swagger. Эта краткость объясняется тем, что дисплей Swagger предназначен для интерактивного взаимодействия, где можно опробовать вызовы и посмотреть ответы — используя свой собственный ключ API, чтобы увидеть свои собственные данные. такой подход получил название: «учись, практикуясь». Кроме того, Swagger UI охватывает только документацию конечных точек. Концептуальные разделы обычно рассматриваются в отдельном руководстве.

👨‍💻 Практическое занятие: Создание спецификации OpenAPI в Swagger UI

На этом занятии мы создадим документацию в Swagger UI в спецификации OpenAPI. Если вы используете один из предварительно созданных файлов OpenAPI, вы можете увидеть демонстрацию того, что мы создадим здесь: OpenWeatherMap Swagger UI или Sunrise/sunset Swagger UI).

OpenWeatherMap

Для интеграции спецификации OpenAPI в Swagger UI:

  • Подготавливаем действительный документ спецификации OpenAPI:
    • Инструкции по созданию документа спецификации OpenAPI с нуля см. В обзоре руководства по OpenAPI.
    • Для использования предварительно созданного документа в спецификации OpenAPI, можно использовать файл спецификации OpenWeatherMap или файл спецификации Sunrise/sunset API (Клик правой кнопкой мыши ссылку и сохраните файл YAML на рабочем столе.)
  • Нужно убедиться, что спецификация OpenAPI действительна. Для этого вставляем свой код спецификации OpenAPI в онлайн-редактор Swagger и видим, что слева не отображаются никакие предупреждения. Вид справа в редакторе Swagger показывает полностью функциональный дисплей Swagger UI.
  • Переходим в проект Swagger UI на GitHub
  • Нажмите Clone or download, а затем нажмите Download ZIP. Загрузите файлы в удобное место на вашем компьютере и распакуйте файлы.

Единственная папка, с которой мы будем работать в загруженном zip-архиве, — это папка dist (сокращение от дистрибутива). Все остальное используется, только если мы перекомпилируем файлы Swagger, что выходит за рамки этого руководства.

  • Извлечем папку dist из папки swagger-ui-master в другой каталог. (После этого папку swagger-ui-master и zip-файл можно удалить.)
  • Перетащим файл спецификации OpenAPI (из шага 1) в папку dist. (Если вы используете предварительно созданные файлы OpenAPI, файл называется либо openapi_openweathermap.yml, либо openapi_sunrise_sunset.yml.) Ваша файловая структура должна выглядеть следующим образом:

      ├── dist
      │   ├── favicon-16x16.png
      │   ├── favicon-32x32.png
      │   ├── index.html
      │   ├── oauth2-redirect.html
      │   ├── swagger-ui-bundle.js
      │   ├── swagger-ui-bundle.js.map
      │   ├── swagger-ui-standalone-preset.js
      │   ├── swagger-ui-standalone-preset.js.map
      │   ├── swagger-ui.css
      │   ├── swagger-ui.css.map
      │   ├── swagger-ui.js
      │   ├── swagger-ui.js.map
      │   ├── swagger30.yml
      │   └── [your openapi specification file]
    
  • В папке dist открываем index.html в текстовом редакторе, таком как Atom илиSublime Text.
  • Ищем следующий код:
url: "http://petstore.swagger.io/v2/swagger.json"
  • Меняем значение url на относительный путь к вашему файлу YAML, а затем сохраните файл. Например
url: "openapi_openweathermap.yml",

или

url: "openapi_sunrise_sunset.yml",
  • Изучим файл index.html локально в браузере. Стоит обратить внимание, что ограничения безопасности Chrome (возражения CORS) не позволяют просматривать файл Swagger UI локально. Но есть несколько обходных путей:
    • Просмотр файла локально с помощью Firefox (это самый простой способ);
    • Использование размещенного в Интернете URL-адреса openapi_openweathermap.yml или openapi_sunrise_sunset.yml. (Клик правой кнопкой мыши ссылку и выберите «Копировать адрес ссылки».);
    • Загрузка папки dist на веб-сервер и просмотр ее содержимого на сервере;
    • Поместить файл YAML в общедоступный GitHub Gist и затем нажать Raw. Использовать URL для этого Gist;
    • Использовать локальный сервер, такой как simple local HTTP server.

Когда файл Swagger UI будет готов к публикации, просто загружаем папку на веб-сервер и переходим в файл index.html. Например, если название каталога dist осталось без изменений, переходим по адресу http://myserver.com/dist/. (Имя папки dist можно менять на любое другое.)

Конфигурация параметров Swagger UI

Swagger UI предоставляет различные параметры конфигурации (не связанные с параметрами OpenAPI), которые можно использовать для настройки интерактивного дисплея. Например, можно указать, будет ли каждая конечная точка развернута или свернута, как будут сортироваться теги и операции, показывать ли заголовки запросов в ответе, включать ли раздел «Модели» после списка конечных точек и многое другое.

В этом руководстве не будем вдаваться в подробности этих параметров конфигурации.

Если посмотреть на код демонстрации пользовательского интерфейса Swagger (перейдите в View> Source), то увидим параметры, перечисленные в разделе // Build a system:

  // Build a system
const ui = SwaggerUIBundle({
  url: "openapi_openweathermap.yml",
  dom_id: '#swagger-ui',
  defaultModelsExpandDepth: -1,
  deepLinking: true,
  presets: [
    SwaggerUIBundle.presets.apis,
    SwaggerUIStandalonePreset
  ],
  plugins: [
    SwaggerUIBundle.plugins.DownloadUrl
  ],
  layout: "StandaloneLayout"
})

Все параметры (например, deepLinking, dom_id и т. Д.) являются значениями по умолчанию. Добавлен defaultModelsExpandDepth: -1, чтобы скрыть раздел «Модели» в нижней части экрана Swagger UI.

О параметрах конфигурации Swagger UI можете узнать в документации Swagger.

Проблемы Swagger UI

Изучая интерфейс Swagger, можно заметить несколько ограничений:

  • Не так много места для подробного описания работы конечных точек. При наличии нескольких абзацев с подробностями и сведениями о параметре, лучше всего ссылаться из описания на другую страницу в документации. Спецификация OpenAPI предоставляет способ ссылки на внешнюю документацию как в объекте paths, так и в объекте info, а также и в объекте externalDocs.
  • Интерфейс Swagger выглядит практически одинаково для каждого API. Можно настроить Swagger UI под свои собственные бренды, но понадобятся навыки UX. Относительно легко изменить цвет и изображение в верхней панели навигации.
  • Swagger UI может быть отдельным сайтом от другой документации. Это означает, что в своей документации потребуется ссылаться на Swagger в качестве ссылки для конечных точек. В разделе «Интеграция Swagger UI с остальными документами», описаны стратегии объединения справочных документов и руководства пользователя.

Устранение неполадок

При настройке Swagger UI, могут возникать проблемы. Следующие проблемы являются наиболее распространенными:

Проблема CORS

Если безопасность правильно настроена, но запросы отклоняются, это может быть связано с проблемой CORS (cross-origin resource sharing). CORS — это мера безопасности, которую веб-сайты внедряют, чтобы другие сценарии и процессы не могли получать свое содержимое через запросы от удаленных серверов. Подробности см. В разделе «Поддержка CORS» в документации по интерфейсу Swagger.

Если запросы не работают, переходим в консоль JavaScript браузера (в Chrome, View> Developer> Javascript Console), делаем запрос, и смотрим, относится ли ошибка к запросам разных источников. Если это так, можно попросить разработчиков включить CORS на конечных точках.

Проблемы с url хоста

Хост тестового сервера может быть еще одной причиной отклонения запросов. Некоторые API (например, Aeris Weather) требуют, создания идентификатор приложения на основе URL-адреса хоста, на котором будут выполняться запросы. Если зарегистрированным URL-адресом хоста является http://mysite.com, но тест отправляется по адресу https://editor.swagger.io/, сервер API отклонит запросы.

Встраивание Swagger UI в существующий сайт

Помимо публикации выходных данных пользовательского интерфейса Swagger в качестве отдельного сайта, можно встраивать файл Swagger в существующий сайт. Описание можно посмотреть здесь:

  • Standalone Swagger UI Demo
  • Embedded Swagger UI Demo

Swagger UI адаптивен и хорошо масштабируется, что позволяет вписать его практически в любое пространство. Тем не менее, встроенный в существующий сайт Swagger выглядит как сайт внутри сайта.

🔙

Go next ➡

Swagger UI предоставляет Фреймворк, который читает спецификацию OpenAPI. и создает веб-страницу с интерактивной документацией. В этом руководстве показано, как интегрировать документ спецификации OpenAPI в интерфейс Swagger.

Концептуальный обзор OpenAPI и Swagger можно посмотреть в разделе Знакомство со спецификациями OpenAPI и Swagger. Пошаговое руководство по созданию документа спецификации OpenAPI смотрим в Обзоре руководства OpenAPI 3.0.

Содержание раздела

Обзор Swagger UI

Знакомство со Swagger при помощи Petstore

  • Авторизация запроса

  • Создание запроса

  • Проверка создания питомца

Примеры сайтов с документаций по Swagger UI

Практическое занятие: Создание спецификации OpenAPI в Swagger UI

Конфигурация параметров Swagger UI

Проблемы Swagger UI

Устранение неполадок

Встраивание Swagger UI в существующий сайт

Обзор Swagger UI

Swagger UI — один из самых популярных инструментов для создания интерактивной документации. Swagger UI создает интерактивную консоль API для экспериментов с запросами в реальном времени. Кроме того, Swagger UI (активно управляемый проект с лицензией Apache 2.0) поддерживает последнюю версию спецификации OpenAPI (3.x) и интегрируется с другими инструментами Swagger.

Прежде чем мы углубимся в Swagger, нужно прояснить ключевые термины.

Swagger

Относится к инструментам API, связанным со спецификацией OpenAPI. Некоторыми из этих инструментов являются Swagger Editor, Swagger UI, Swagger Codegen, SwaggerHub и другие. Всеми инструментами управляет компания Smartbear. Для получения дополнительной информации см. Инструменты Swagger. «Swagger» являлся изначально оригинальным названием спецификации OpenAPI, но позже имя было изменено на OpenAPI, чтобы усилить открытый, не лицензионный характер стандарта. Люди иногда ссылаются на оба имени взаимозаменяемо (особенно на старых веб-страницах), но «OpenAPI» — это то, как следует обращаться к спецификации. Дополнительные сведения о разнице между OpenAPI и Swagger см. В разделе «В чем разница между Swagger и OpenAPI?».

OpenAPI

Официальное название спецификации OpenAPI. Спецификация OpenAPI предоставляет набор свойств, которые можно использовать для описания REST API. Рабочий, валидный документ можно использовать для создания интерактивной документации, создания клиентских SDK, запуска модульных тестов и многого другого. Подробности спецификации можно изучить на GitHub по адресу https://github.com/OAI/OpenAPI-Specification. В рамках инициативы Open API с Linux Foundation спецификация OpenAPI направлена ​​на то, чтобы быть независимой от производителя (многие компании участвуют в ее разработке).

Swagger Editor

Онлайн-редактор, который проверяет документацию OpenAPI на соответствие правилам спецификации OpenAPI. Редактор Swagger помечает ошибки и дает советы по форматированию.

Swagger UI

Веб-фрэймворк (на GitHub), который анализирует документ в спецификации OpenAPI и создает веб-страницу интерактивной документации. Swagger UI — это инструмент, который превращает спецификацию в подобный Petstore-сайт.

Swagger Codegen

Генерирует код SDK для множества различных платформ (таких как Java, JavaScript, Scala, Python, PHP, Ruby, Scala и другие). Код SDK помогает разработчикам интегрировать API на конкретной платформе и обеспечивает более надежные реализации, которые могут включать в себя больше масштабирования, многопоточности и т.д.. В общем, SDK — это наборы инструментов для реализации запросов, сделанных с помощью API. Swagger Codegen генерирует клиентские SDK практически на каждом языке программирования. См. Swagger Codegen для получения дополнительной информации. Смотрите также SDK и примеры приложений.

Знакомство со Swagger при помощи Petstore

Чтобы лучше понять интерфейс Swagger, давайте рассмотрим пример Swagger Petstore. В примере Petstore сайт генерируется с помощью Swagger UI.

Petstore

Конечные точки сгруппированы следующим образом:

  • pet
  • store
  • user

Авторизация запроса

Прежде чем делать какие-либо запросы, нужна авторизация. Нажимаем кнопку Authorize и заполняем информацию, требуемую в окне «Авторизация», изображенном ниже:

Authorize

Пример Petstore имеет модель безопасности OAuth 2.0. Код авторизации только для демонстрационных целей. Нет никакой реальной логики авторизации этих запросов, поэтому просто закрываем окно Авторизации.

Создание запроса

Теперь создадим запрос:

  1. Развернем конечную точку POST Pet
  2. Нажимаем кнопку Try it out

Try it out

После того, как мы нажмем кнопку Try it out, значение примера в поле «Тело запроса» станет редактируемым.

  1. В поле «Example Value» изменяем первое значение id на случайное целое число, например 193844. Также значение второго name на другое (имя вашего питомца).
  2. Нажимаем Execute

Execute

Выполнение примера запроса Petstore

Пользовательский интерфейс Swagger отправляет запрос и показывает отправленный curl. Раздел Ответы показывает ответ. (Если выбрать JSON вместо XML в раскрывающемся списке «Response content type», формат ответа будет показан в формате JSON.)

Response

!Важно! Petstore — это функционирующий API, и вы фактически создали питомца. Теперь вам нужно взять на себя ответственность за вашего питомца и начать кормить и ухаживать за ним! Шутки, шутками, но большинство пользователей не осознают, что играют с реальными данными, когда выполняют ответы в API (особенно при использовании своего собственного ключа API). Эти тестовые данные могут быть чем-то, что вам придется стереть при переходе от исследований и изучения API к использованию API для реального использования.

Проверка создания питомца

  1. Разворачиваем точку GET /pet/{petId}
  2. Нажимаем кнопку Try it out
  3. Вводим ID питомца, который использовали в предыдущей операции. (Если забыли ID, посмотрите на конечную точку POST Pet, чтобы проверить значение.)
  4. Нажимаем Execute . В ответе мы должны увидеть имя нашего питомца.

Примеры сайтов с документаций по Swagger UI

Прежде чем мы перейдем к другому API с этим пособием по Swagger (кроме демонстрации Petstore), посмотрим на другие реализации Swagger:

  • Reverb
  • VocaDB
  • Watson Developer Cloud
  • The Movie Database API
  • Zomato API

Некоторые из этих сайтов выглядят одинаково, но другие, такие как The Movie Database API и Zomato, были легко интегрированы в остальную часть их сайта документации.

Глядя на примеры, можно заметить краткость документации в реализации Swagger. Эта краткость объясняется тем, что дисплей Swagger предназначен для интерактивного взаимодействия, где можно опробовать вызовы и посмотреть ответы — используя свой собственный ключ API, чтобы увидеть свои собственные данные. такой подход получил название: «учись, практикуясь». Кроме того, Swagger UI охватывает только адресные темы документации. Концептуальные разделы обычно рассматриваются в отдельном руководстве.

👨‍💻 Практическое занятие: Создание спецификации OpenAPI в Swagger UI

На этом занятии мы создадим документацию в Swagger UI в спецификации OpenAPI. Если вы используете один из предварительно созданных файлов OpenAPI, вы можете увидеть демонстрацию того, что мы создадим здесь: OpenWeatherMap Swagger UI или Sunrise/sunset Swagger UI).

OpenWeatherMap

Для интеграции спецификации OpenAPI в Swagger UI:

  1. Подготавливаем действительный документ спецификации OpenAPI:
  • Инструкции по созданию документа спецификации OpenAPI с нуля см. В обзоре руководства по OpenAPI.
  • Для использования предварительно созданного документа в спецификации OpenAPI, можно использовать файл спецификации OpenWeatherMap или файл спецификации Sunrise/sunset API (Клик правой кнопкой мыши ссылку и сохраните файл YAML на рабочем столе.)
  1. Нужно убедиться, что спецификация OpenAPI действительна. Для этого вставляем свой код спецификации OpenAPI в онлайн-редактор Swagger и видим, что слева не отображаются никакие предупреждения. Вид справа в редакторе Swagger показывает полностью функциональный дисплей Swagger UI.
  2. Переходим в проект Swagger UI на GitHub
  3. Нажмите Clone or download, а затем нажмите Download ZIP. Загрузите файлы в удобное место на вашем компьютере и распакуйте файлы.

Единственная папка, с которой мы будем работать в загруженном zip-архиве, — это папка dist (сокращение от дистрибутива). Все остальное используется, только если мы перекомпилируем файлы Swagger, что выходит за рамки этого руководства.

  1. Извлечем папку dist из папки swagger-ui-master в другой каталог. (После этого папку swagger-ui-master и zip-файл можно удалить.)

  2. Перетащим файл спецификации OpenAPI (из шага 1) в папку dist. (Если вы используете предварительно созданные файлы OpenAPI, файл называется либо openapi_openweathermap.yml, либо openapi_sunrise_sunset.yml.) Ваша файловая структура должна выглядеть следующим образом:

     ├── dist
     │   ├── favicon-16x16.png
     │   ├── favicon-32x32.png
     │   ├── index.html
     │   ├── oauth2-redirect.html
     │   ├── swagger-ui-bundle.js
     │   ├── swagger-ui-bundle.js.map
     │   ├── swagger-ui-standalone-preset.js
     │   ├── swagger-ui-standalone-preset.js.map
     │   ├── swagger-ui.css
     │   ├── swagger-ui.css.map
     │   ├── swagger-ui.js
     │   ├── swagger-ui.js.map
     │   ├── swagger30.yml
     │   └── [your openapi specification file]
    
  3. В папке dist открываем index.html в текстовом редакторе, таком как Atom илиSublime Text.

  4. Ищем следующий код:
    url: «http://petstore.swagger.io/v2/swagger.json»,

  5. Меняем значение url на относительный путь к вашему файлу YAML, а затем сохраните файл. Например

url: "openapi_openweathermap.yml",

или

url: "openapi_sunrise_sunset.yml",
  1. Изучим файл index.html локально в браузере. Стоит обратить внимание, что ограничения безопасности Chrome (возражения CORS) не позволяют просматривать файл Swagger UI локально. Но есть несколько обходных путей:
  • Просмотр файла локально с помощью Firefox (это самый простой способ);
  • Использование размещенного в Интернете URL-адреса openapi_openweathermap.yml или openapi_sunrise_sunset.yml. (Клик правой кнопкой мыши ссылку и выберите «Копировать адрес ссылки».);
  • Загрузка папки dist на веб-сервер и просмотр ее содержимого на сервере;
  • Поместить файл YAML в общедоступный GitHub Gist и затем нажать Raw. Использовать URL для этого Gist;
  • Использовать локальный сервер, такой как simple local HTTP server.

Когда файл Swagger UI будет готов к публикации, просто загружаем папку на веб-сервер и переходим в файл index.html. Например, если название каталога dist осталось без изменений, переходим по адресу http://myserver.com/dist/. (Имя папки dist можно менять на любое другое.)

Для получения дополнительных инструкций по работе с Swagger UI см. Документацию Swagger.io.

Конфигурация параметров Swagger UI

Swagger UI предоставляет различные параметры конфигурации (не связанные с параметрами OpenAPI), которые можно использовать для настройки интерактивного дисплея. Например, можно указать, будет ли каждая конечная точка развернута или свернута, как будут сортироваться теги и операции, показывать ли заголовки запросов в ответе, включать ли раздел «Модели» после списка конечных точек и многое другое.

В этом руководстве не будем вдаваться в подробности этих параметров конфигурации.

Если посмотреть на код демонстрации пользовательского интерфейса Swagger (перейдите в View> Source), то увидим параметры, перечисленные в разделе // Build a system:

  // Build a system
const ui = SwaggerUIBundle({
  url: "openapi_openweathermap.yml",
  dom_id: '#swagger-ui',
  defaultModelsExpandDepth: -1,
  deepLinking: true,
  presets: [
    SwaggerUIBundle.presets.apis,
    SwaggerUIStandalonePreset
  ],
  plugins: [
    SwaggerUIBundle.plugins.DownloadUrl
  ],
  layout: "StandaloneLayout"
})

Все параметры (например, deepLinking, dom_id и т. Д.) являются значениями по умолчанию. Добавлен defaultModelsExpandDepth: -1, чтобы скрыть раздел «Модели» в нижней части экрана Swagger UI.

О параметрах конфигурации Swagger UI можете узнать в документации Swagger.

Проблемы Swagger UI

Изучая интерфейс Swagger, можно заметить несколько ограничений:

  • Не так много места для подробного описания работы конечных точек. При наличии нескольких абзацев с подробностями и сведениями о параметре, лучше всего ссылаться из описания на другую страницу в документации. Спецификация OpenAPI предоставляет способ ссылки на внешнюю документацию как в объекте paths, так и в объекте info, а также и в объекте externalDocs.
  • Интерфейс Swagger выглядит практически одинаково для каждого API. Можно настроить Swagger UI под свои собственные бренды, но понадобятся навыки UX. Относительно легко изменить цвет и изображение в верхней панели навигации.
  • Swagger UI может быть отдельным сайтом от другой документации. Это означает, что в своей документации потребуется ссылаться на Swagger в качестве ссылки для конечных точек. В разделе «Интеграция Swagger UI с остальными документами», описаны стратегии объединения справочных документов и руководства пользователя.

Устранение неполадок

При настройке Swagger UI, могут возникать проблемы. Следующие проблемы являются наиболее распространенными:

Проблема CORS

Если безопасность правильно настроена, но запросы отклоняются, это может быть связано с проблемой CORS (cross-origin resource sharing). CORS — это мера безопасности, которую веб-сайты внедряют, чтобы другие сценарии и процессы не могли получать свое содержимое через запросы от удаленных серверов. Подробности см. В разделе «Поддержка CORS» в документации по интерфейсу Swagger.

Если запросы не работают, переходим в консоль JavaScript браузера (в Chrome, View> Developer> Javascript Console), делаем запрос, и смотрим, относится ли ошибка к запросам разных источников. Если это так, можно попросить разработчиков включить CORS на конечных точках.

Проблемы с url хоста

Хост тестового сервера может быть еще одной причиной отклонения запросов. Некоторые API (например, Aeris Weather) требуют, создания идентификатор приложения на основе URL-адреса хоста, на котором будут выполняться запросы. Если зарегистрированным URL-адресом хоста является http://mysite.com, но тест отправляется по адресу https://editor.swagger.io/, сервер API отклонит запросы.

Встраивание Swagger UI в существующий сайт

Помимо публикации выходных данных пользовательского интерфейса Swagger в качестве отдельного сайта, можно встраивать файл Swagger в существующий сайт. Описание можно посмотреть здесь:

  • Standalone Swagger UI Demo
  • Embedded Swagger UI Demo

Swagger UI адаптивен и хорошо масштабируется, что позволяет вписать его практически в любое пространство. Тем не менее, встроенный в существующий сайт Swagger выглядит как сайт внутри сайта.

🔙

Go next ➡

Время на прочтение
9 мин

Количество просмотров 218K

Всем привет!!! Это мой первый пост на Хабре и я хочу поделиться с вами своим опытом в исследовании нового для себя фреймворка.

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

Сейчас хочу поделиться ею в надежде, что кому-то она поможет в изучение Swagger (OpenApi 3.0)

Введение

Я на 99% уверен у многих из вас были проблемы с поиском документации для нужного вам контроллера. Многие если и находили ее быстро, но в конечном итоге оказывалось что она работает не так как описано в документации, либо вообще его уже нет.
Сегодня я вам докажу, что есть способы поддерживать документацию в актуальном виде и в этом мне будет помогать Open Source framework от компании SmartBear под названием Swagger, а с 2016 года он получил новое обновление и стал называться OpenAPI Specification.

Swagger — это фреймворк для спецификации RESTful API. Его прелесть заключается в том, что он дает возможность не только интерактивно просматривать спецификацию, но и отправлять запросы – так называемый Swagger UI.

Также возможно сгенерировать непосредственно клиента или сервер по спецификации API Swagger, для этого понадобится Swagger Codegen.

Основные подходы

Swagger имеет два подхода к написанию документации:

  • Документация пишется на основании вашего кода.

    • Данный подход позиционируется как «очень просто». Нам достаточно добавить несколько зависимостей в проект, добавить конфигурацию и уже мы будем иметь нужную документацию, хоть и не настолько описанной какою мы хотели.

    • Код проекта становится не очень читабельным от обилия аннотаций и описания в них.

    • Вся документация будет вписана в нашем коде (все контроллеры и модели превращаются в некий Java Swagger Code)

    • Подход не советуют использовать, если есть возможности, но его очень просто интегрировать.

  • Документация пишется отдельно от кода.

    • Данный подход требует знать синтаксис Swagger Specification.

    • Документация пишется либо в YAML/JSON файле, либо в редакторе Swagger Editor.

Swagger Tools

Swagger или OpenAPI framework состоит из 4 основных компонентов:

  1. Swagger Core — позволяет генерировать документацию на основе существующего кода основываясь на Java Annotation.

  2. Swagger Codegen — позволит генерировать клиентов для существующей документации.

  3. Swagger UI — красивый интерфейс, который представляет документацию. Дает возможность просмотреть какие типы запросов есть, описание моделей и их типов данных.

  4. Swagger Editor — Позволяет писать документацию в YAML или JSON формата.

Теперь давайте поговорим о каждом компоненте отдельно.

Swagger Core

Swagger Code — это Java-реализация спецификации OpenAPI

Для того что бы использовать Swagger Core во все орудие, требуется:

  • Java 8 или больше

  • Apache Maven 3.0.3 или больше

  • Jackson 2.4.5 или больше

Что бы внедрить его в проект, достаточно добавить две зависимости:

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>2.1.6</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.5.2</version>
</dependency>

Также можно настроить maven плагин, что бы наша документация при сборке проект генерировалсь в YAML

<plugin>
 <groupId>org.springdoc</groupId>
 <artifactId>springdoc-openapi-maven-plugin</artifactId>
 <version>0.3</version>
 <executions>
   <execution>
   <phase>integration-test</phase>
   <goals>
     <goal>generate</goal>
   </goals>
   </execution>
 </executions>
 <configuration>
   <apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl>
   <outputFileName>openapi.yaml</outputFileName>
   <outputDir>${project.build.directory}</outputDir>
 </configuration>
</plugin>

Дальше нам необходимо добавить конфиг в проект.

Для конфигурации Swagger необходимо добавить два бина. Где нам нужно будет описать название приложения, версию нашего API, так же можно добавить контакт разработчика, который отвечает за данные API.

    @Bean
    public GroupedOpenApi publicUserApi() {
        return GroupedOpenApi.builder()
                             .group("Users")
                             .pathsToMatch("/users/**")
                             .build();
    }

    @Bean
    public OpenAPI customOpenApi(@Value("${application-description}")String appDescription,
                                 @Value("${application-version}")String appVersion) {
        return new OpenAPI().info(new Info().title("Application API")
                                            .version(appVersion)
                                            .description(appDescription)
                                            .license(new License().name("Apache 2.0")
                                                                  .url("http://springdoc.org"))
                                            .contact(new Contact().name("username")
                                                                  .email("test@gmail.com")))
                            .servers(List.of(new Server().url("http://localhost:8080")
                                                         .description("Dev service"),
                                             new Server().url("http://localhost:8082")
                                                         .description("Beta service")));
    }

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

Вот некоторые из них:

  • @Operation — Описывает операцию или обычно метод HTTP для определенного пути.

  • @Parameter — Представляет один параметр в операции OpenAPI.

  • @RequestBody — Представляет тело запроса в операции

  • @ApiResponse — Представляет ответ в операции

  • @Tag — Представляет теги для операции или определения OpenAPI.

  • @Server — Представляет серверы для операции или для определения OpenAPI.

  • @Callback — Описывает набор запросов

  • @Link — Представляет возможную ссылку времени разработки для ответа.

  • @Schema — Позволяет определять входные и выходные данные.

  • @ArraySchema — Позволяет определять входные и выходные данные для типов массивов.

  • @Content — Предоставляет схему и примеры для определенного типа мультимедиа.

  • @Hidden — Скрывает ресурс, операцию или свойство

Примеры использования:

@Tag(name = "User", description = "The User API")
@RestController
public class UserController {}
    @Operation(summary = "Gets all users", tags = "user")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Found the users",
                    content = {
                            @Content(
                                    mediaType = "application/json",
                                    array = @ArraySchema(schema = @Schema(implementation = UserApi.class)))
                    })
    })
    @GetMapping("/users")
    public List<UserApi> getUsers()

Swagger Codegen

Swagger Codegen — это проект, который позволяет автоматически создавать клиентские библиотеки API (создание SDK), заглушки сервера и документацию с учетом спецификации OpenAPI.

В настоящее время поддерживаются следующие языки / фреймворки:

  • API clients:

    • Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured)

    • Kotlin

    • Scala (akka, http4s, swagger-async-httpclient)

    • Groovy

    • Node.js (ES5, ES6, AngularJS with Google Closure Compiler annotations)

    • Haskell (http-client, Servant)

    • C# (.net 2.0, 3.5 or later)

    • C++ (cpprest, Qt5, Tizen)

    • Bash

  • Server stub:

    • Java (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, PKMST)

    • Kotlin

    • C# (ASP.NET Core, NancyFx)

    • C++ (Pistache, Restbed)

    • Haskell (Servant)

    • PHP (Lumen, Slim, Silex, Symfony, Zend Expressive)

    • Python (Flask)

    • NodeJS

    • Ruby (Sinatra, Rails5)

    • Rust (rust-server)

    • Scala (Finch, Lagom, Scalatra)

  • API documentation generators:

    • HTML

    • Confluence Wiki

  • Other:

    • JMeter

Что бы внедрить его в проект, достаточно добавить зависимость, если используете Swagger:

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.4.18</version>
</dependency>

и если используете OpenApi 3.0, то:

<dependency>
    <groupId>io.swagger.codegen.v3</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>3.0.24</version>
</dependency>

Можно настроить maven плагин, и уже на процессе сборки мы можем сгенерировать нужный для нас клиент либо мок сервиса.

      <plugin>
        <groupId>org.openapitools</groupId>
        <artifactId>openapi-generator-maven-plugin</artifactId>
        <version>3.3.4</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <generatorName>spring</generatorName>
              <inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
              <output>${project.build.directory}/generated-sources</output>
              <apiPackage>com.api</apiPackage>
              <modelPackage>com.model</modelPackage>
              <supportingFilesToGenerate>
                ApiUtil.java
              </supportingFilesToGenerate>
              <configOptions>
                <groupId>${project.groupId}</groupId>
                <artifactId>${project.artifactId}</artifactId>
                <artifactVersion>${project.version}</artifactVersion>
                <delegatePattern>true</delegatePattern>
                <sourceFolder>swagger</sourceFolder>
                <library>spring-mvc</library>
                <interfaceOnly>true</interfaceOnly>
                <useBeanValidation>true</useBeanValidation>
                <dateLibrary>java8</dateLibrary>
                <java8>true</java8>
              </configOptions>
              <ignoreFileOverride>${project.basedir}/.openapi-generator-ignore</ignoreFileOverride>
            </configuration>
          </execution>
        </executions>
      </plugin>

Также все это можно выполнить с помощью командной строки.

Запустив джарник codegen и задав команду help можно увидеть команды, которые предоставляет нам Swagger Codegen:

  • config-help — Справка по настройке для выбранного языка

  • generate — Сгенерировать код с указанным генератором

  • help — Отображение справочной информации об openapi-generator

  • list — Перечисляет доступные генераторы

  • meta — Генератор для создания нового набора шаблонов и конфигурации для Codegen. Вывод будет основан на указанном вами языке и будет включать шаблоны по умолчанию.

  • validate — Проверить спецификацию

  • version — Показать информацию о версии, используемую в инструментах

Для нас самые нужные команды это validate, которая быстро проверять на валидность спецификации и generate, с помощью которой мы можем сгенерировать Client на языке Java

  • java -jar openapi-generator-cli-4.3.1.jar validate -i openapi.yaml

  •  java -jar openapi-generator-cli-4.3.1.jar generate -i openapi.yaml -g java —library jersey2 -o client-gener-new

Swagger UI

Swagger UI — позволяет визуализировать ресурсы API и взаимодействовать с ними без какой-либо логики реализации. Он автоматически генерируется из вашей спецификации OpenAPI (ранее известной как Swagger), а визуальная документация упрощает внутреннюю реализацию и использование на стороне клиента.

Вот пример Swagger UI который визуализирует документацию для моего pet-project:

Нажавши на кнопку «Try it out», мы можем выполнить запрос за сервер и получить ответ от него:

Swagger Editor

Swagger Editor — позволяет редактировать спецификации Swagger API в YAML внутри вашего браузера и просматривать документацию в режиме реального времени. Затем можно сгенерировать допустимые описания Swagger JSON и использовать их с полным набором инструментов Swagger (генерация кода, документация и т. Д.).

На верхнем уровне в спецификации OpenAPI 3.0 существует восемь объектов. Внутри этих верхнеуровневых объектов есть много вложенных объектов, но на верхнем уровне есть только следующие объекты:

  1. openapi

  2. info

  3. servers

  4. paths

  5. components

  6. security

  7. tags

  8. externalDocs

Для работы над документацией со спецификацией используется онлайн-редактор Swagger Редактор Swagger имеет разделенное представление: слева пишем код спецификации, а справа видим полнофункциональный дисплей Swagger UI. Можно даже отправлять запросы из интерфейса Swagger в этом редакторе.

Редактор Swagger проверит контент в режиме реального времени, и укажет ошибки валидации, во время кодирования документа спецификации. Не стоит беспокоиться об ошибках, если отсутствуют X-метки в коде, над которым идет работа.

Первым и важным свойством для документации это openapi. В объекте указывается версия спецификации OpenAPI. Для Swagger спецификации это свойство будет swagger:

 openapi: "3.0.2"

Объект info содержит основную информацию о вашем API,включая заголовок, описание, версию, ссылку на лицензию, ссылку на обслуживания и контактную информацию. Многие из этих свойство являются не обязательными.

info:
  title: "OpenWeatherMap API"
  description: "Get the current weather, daily forecast for 16 days, and a three-hour-interval forecast for 5 days for your city."
  version: "2.5"
  termsOfService: "https://openweathermap.org/terms"
  contact:
  	name: "OpenWeatherMap API"
    url: "https://openweathermap.org/api"
    email: "some_email@gmail.com"
  license:
    name: "CC Attribution-ShareAlike 4.0 (CC BY-SA 4.0)"
    url: "https://openweathermap.org/price"

Объект servers указывает базовый путь, используемый в ваших запросах API. Базовый путь — это часть URL, которая находится перед конечной точкой. Объект servers обладает гибкой настройкой. Можно указать несколько URL-адресов:

servers:
  - url: https://api.openweathermap.org/data/2.5/
        description: Production server
  - url: http://beta.api.openweathermap.org/data/2.5/
        description: Beta server
  - url: http://some-other.api.openweathermap.org/data/2.5/
        description: Some other server

paths — Это та же “конечная точка” в соответствии с терминологии спецификации OpenAPI. Каждый объект path содержит объект operations — это методы GET, POST, PUT, DELETE:

paths:
  /weather:
     get:

Объект components уникален среди других объектов в спецификации OpenAPI. В components хранятся переиспользуемые определения, которые могут появляться в нескольких местах в документе спецификации. В нашем сценарии документации API мы будем хранить детали для объектов parameters и responses в объекте components

Conclusions

  • Документация стала более понятней для бизнес юзера так и для техническим юзерам (Swagger UI, Open Specifiation)

  • Может генерировать код для Java, PHP, .NET, JavaScrypt (Swager Editor, Swagger Codegen)

  • Можно проверять насколько совместимы изменения. Можно настраивать это в дженкинсе

  • Нет ни какой лишней документации к коде, код отдельно, документация отдельно

Создание документации вручную — утомительный процесс. В этой статье мы рассмотрим основы Swagger и его возможности по документированию REST API в SpringBoot приложении.

Спонсор поста

Используемые версии

Java 17
Spring Boot 3.0.2
Swagger 2.2.8
SpringDoc 1.6.14 | 2.0.2

Изменения статьи

29.06.22: Обновил до Java 17. Обновил все зависимости до актуальных.
11.02.23: Обновил SpringBoot до 3.0.2. Обновил остальные зависимости. Добавил раздел с авторизацией в Swagger UI.

Swagger позволяет разработчикам описывать структуру своих API и генерировать интерактивную документацию, клиентские библиотеки и серверные модули для реализации API на разных языках.

Swagger предоставляет спецификацию для документирования REST API, которая называется OpenAPI Specification (OAS). Эта спецификация предоставляет четкий и лаконичный способ описания эндпойнтов, их параметров, моделей запросов и ответов и других аспектов API.

В данной статье рассматривается пример генерации OAS на основе уже существующих REST контроллеров. Мы разметим контроллеры и эндпойнты аннотациями, на основе которых будет сгенерирована OAS.

Существуют библиотеки, которые на основе OAS могут сгенерировать интерактивную документацию для API, которая позволит отправлять запросы, и получать ответы. Мы воспользуемся библиотекой SpringDoc.

Почему SpringDoc, а не SpringFox?

В интернете множество статей с использованием библиотеки SpringFox для генерации Swagger UI. Почему тогда я использую какой-то SpringDoc?

SpringFox был заброшен авторами. Последний коммит сделан в 2020 году, а количество issue уже перевалило за 200. В какой-то момент я столкнулся с каким-то багом в SpringFox, который никогда не будет исправлен, и стал искать альтернативы.

Такой альтернативой оказался SpringDoc, который активно развивается и поддерживает SpringBoot 3. Я успешно и быстро перевел свой проект с SpringFox на SpringDoc.

Также стоит упомянуть, что Swagger позволяет сгенерировать непосредственно код клиента или сервера по имеющейся OAS, для этого нужен генератор кода Swagger-Codegen.

Генератором я никогда не пользовался. Генерируемый код получается весьма неказистым и проще написать его самостоятельно.

Демо проект с REST API

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

Добавим примитивные контроллеры и одно DTO. Бизнес суть нашей системы – программа лояльности пользователей.

Для наших примеров достаточно слоя контроллеров, поэтому я позволю себе вольность опустить серверный и репозиторный слой и добавить бизнес логику непосредственно контроллер.

В качестве DTO у нас будет класс UserDto – это пользователь нашей системы. У него пять полей, из которых 3 обязательны.

UserDto.java

public class UserDto {

    private String key;
    private String name;
    private Long points = 0L;
    private Gender gender;
    private LocalDateTime regDate = LocalDateTime.now();

    public UserDto() {
    }

    public UserDto(String key, String name, Gender gender) {
        this.key = key;
        this.name = name;
        this.gender = gender;
    }

    public static UserDto of(String key, String value, Gender gender) {
        return new UserDto(key, value, gender);
    }

    // getters and setters

}
public enum Gender {
    MAN, WOMAN
}

Для взаимодействия с нашей бизнес-логикой, добавим три контроллера: UserController, PointContoller, SecretContoller.

UserController отвечает за добавление, обновление и получение пользователей.

UserController.java

@RestController
@RequestMapping("/api/user")
public class UserController {

    private final Map<String, UserDto> repository;

    public UserController(Map<String, UserDto> repository) {
        this.repository = repository;
    }

    @PutMapping(produces = APPLICATION_JSON_VALUE)
    public HttpStatus registerUser(@RequestBody UserDto userDto) {
        repository.put(userDto.getKey(), userDto);
        return HttpStatus.OK;
    }

    @PostMapping(produces = APPLICATION_JSON_VALUE)
    public HttpStatus updateUser(@RequestBody UserDto userDto) {
        if (!repository.containsKey(userDto.getKey())) return HttpStatus.NOT_FOUND;
        repository.put(userDto.getKey(), userDto);
        return HttpStatus.OK;
    }

    @GetMapping(value = "{key}", produces = APPLICATION_JSON_VALUE)
    public ResponseEntity<UserDto> getSimpleDto(@PathVariable("key") String key) {
        return ResponseEntity.ok(repository.get(key));
    }

}

PointContoller отвечает за взаимодействие с баллами пользователя. Один метод этого контроллера отвечает за добавление и удаление балов пользователям.

PointContoller.java

@RestController
@RequestMapping("api/user/point")
public class PointController {

    private final Map<String, UserDto> repository;

    public PointController(Map<String, UserDto> repository) {
        this.repository = repository;
    }

    @PostMapping("{key}")
    public HttpStatus changePoints(
            @PathVariable String key,
            @RequestParam("point") Long point,
            @RequestParam("type") String type
    ) {
        final UserDto userDto = repository.get(key);
        userDto.setPoints(
                "plus".equalsIgnoreCase(type)
                    ? userDto.getPoints() + point
                    : userDto.getPoints() - point
        );
        return HttpStatus.OK;
    }

}

Метод destroy в SecretContoller может удалить всех пользователей.

SecretContoller.java

@RestController
@RequestMapping("api/secret")
public class SecretController {

    private final Map<String, UserDto> repository;

    public SecretController(Map<String, UserDto> repository) {
        this.repository = repository;
    }

    @GetMapping(value = "destroy")
    public HttpStatus destroy() {
        repository.clear();
        return HttpStatus.OK;
    }

}

Настраиваем Swagger

😺

Ветка в репозитории: spring-boot-3

Теперь добавим Swagger в наш проект. Для этого добавьте следующие зависимости в pom.xml:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.0.2</version>
</dependency>
Актуальная версия в Maven Central: SpringDoc Starter

Для WebFlux используйте другую зависимость:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
    <version>2.0.2</version>
</dependency>
Актуальная версия в Maven Central: SpringDoc Starter WebFlux

Данные зависимости подходят только для проектов на SpringBoot 3. Если вы используете SpringBoot 2, то вам необходимо добавить другие зависимости:

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>2.2.8</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.14</version>
</dependency>
Актуальные вресии в Maven Central: Swagger, SpringDoc

Swagger автоматически находит список всех контроллеров. При нажатии на любой из них будут перечислены допустимые методы HTTP (DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT).

Для каждого метода доступные следующие данные: статус ответа, тип содержимого и список параметров.

Поэтому после добавления зависимостей у нас уже есть документация, доступная по ссылке: http://localhost:8080/swagger-ui. А также есть OAS, доступный по адресу: http://localhost:8080/v3/api-docs.

Swagger запущенный с дефолтными настройками

Swagger запущенный с дефолтными настройками

Также можно вызвать каждый метод с помощью пользовательского интерфейса. Откроем метод добавления пользователей.

Пока у нас не очень информативная документация. Давайте исправим это. Для начала создадим класс конфигурации сваггера OpenApiConfig — имя произвольное.

@OpenAPIDefinition(
        info = @Info(
                title = "Loyalty System Api",
                description = "Loyalty System", version = "1.0.0",
                contact = @Contact(
                        name = "Struchkov Mark",
                        email = "mark@struchkov.dev",
                        url = "https://mark.struchkov.dev"
                )
        )
)
public class OpenApiConfig {
    
}
  • title – это название вашего приложения.
  • version – версия вашего API.
  • contact – ответственные за API.

Эти данные больше для визуальной красоты UI документации.

Разметка контроллеров

Переопределим описания контроллеров, чтобы сделать документацию понятнее. Для этого пометим контроллеры аннотацией @Tag.

@Tag(name="Название контроллера", description="Описание контролера")
public class ControllerName {

    // ... ... ... ... ...

} 

Добавили описание контроллеров в Swagger

Скрыть контроллер

У нас есть контроллер, который мы хотим скрыть – SecretController. Аннотация @Hidden поможет нам в этом.

@Hidden
@Tag(name = "Секретный контролер", description = "Позволяет удалить всех пользователей")
public class SecretController {

    // ... ... ... ... ...

}

Аннотация скрывает контроллер только из Swagger. Он все также доступен для вызова. Используйте другие методы для защиты вашего API. Например, авторизацию на основе JWT токена.

Наша документация стала намного понятнее, но давайте добавим описания для каждого метода контроллера.

Разметка методов

Аннотация @Operation описывает возможности методов контроллера. Достаточно определить следующие значения:

  • summary – короткое описание.
  • description – более полное описание.
@Operation(
	summary = "Регистрация пользователя",
	description = "Позволяет зарегистрировать пользователя"
)
public HttpStatus registerUser(@RequestBody UserDto userDto) {

    // ... ... ... ... ...

}

Разметка переменных метода

При помощи аннотации Parameter также опишем переменные в методе, который отвечает за управление баллами пользователей.

public HttpStatus changePoints(
    @PathVariable @Parameter(description = "Идентификатор пользователя") String key,
    @RequestParam("point") @Parameter(description = "Количество баллов") Long point,
    @RequestParam("type") @Parameter(description = "Тип операции") TypeOperation type
) {

    // ... ... ... ... ...

}

С помощью параметра required можно задать обязательные поля для запроса. По умолчанию все поля необязательные.

Разметка DTO

Разработчики стараются называть переменные в классе понятными именами, но не всегда это помогает. Вы можете дать человеко-понятное описание самой DTO и ее переменным с помощью аннотации @Schema.

@Schema(description = "Сущность пользователя")
public class UserDto {

    @Schema(description = "Идентификатор")
    private String key;

    // ... ... ... ... ...

}

Сваггер заполнит переменные, формат которых он понимает: enum, даты. Но если некоторые поля DTO имеют специфичный формат, то помогите разработчикам добавив пример.

@Schema(description = "Идентификатор", example = "A-124523")

Выглядеть это будет так:

В разделе Schema и при отправке запроса

Но подождите, зачем мы передаем дату регистрации. Да и уникальный ключ чаще всего будет задаваться сервером. Скроем эти поля из swagger с помощью параметра Schema.AccessMode.READ_ONLY:

public class UserDto {

    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
    private String key;

    // ... ... ... ... ...

}

Валидация

Про валидацию я подробно рассказывал в статье: «Валидация данных в SpringBoot». Здесь я лишь хочу показать, что валидация параметров методов контроллеров также отображается в Swagger.

Добавим валидацию в метод управления баллами пользователя в PointController. Мы не хотим, чтобы можно было передать отрицательные баллы.

public HttpStatus changePoints(
    // ... ... ... ... ...
    @RequestParam("point") @Min(0) @Parameter(description = "Количество баллов") Long point,
    // ... ... ... ... ...
) {

    // ... ... ... ... ...

}

Давайте посмотрим на изменения спецификации.

Для поля point появилось замечание minimum: 0. И все это нам не стоило ни малейшего дополнительного усилия.

Авторизация в Swager

😺

Ветка в репозитории: jwt-auth

Если ваш API защищен авторизаций и аутентификаций, то вы не сможете просто так вызвать запрос из Swagger. Один из самых распространенных способов авторизации это JWT, о нем я рассказывал в отдельной статье.

Сейчас нам нужно объяснить сваггеру, какая авторизация у нас применяется и какие эндпойнты ей защищены.

Авторизация с использованием JWT

В первом случае рассмотрим старый добрый JWT. Swagger должен получить access-токен и добавлять его в Header запросов.

Начнем с добавления аннотации @SecurityScheme над классом OpenApiConfig:

@OpenAPIDefinition(...)
@SecurityScheme(
        name = "JWT",
        type = SecuritySchemeType.HTTP,
        bearerFormat = "JWT",
        scheme = "bearer"
)
public class OpenApiConfig {

}

Мы описали схему авторизации с использованием JWT. Теперь пометим аннотацией @SecurityRequirement все эндпойнты, которые используют данный способ авторизации. В @SecurityRequirement в атрибуте name указываем название нашей схемы – JWT. Название должно совпадать с названием из аннотации @SecurityScheme.

@PostMapping("{key}")
@SecurityRequirement(name = "JWT")
@Operation(summary = "Управление баллами", description = "Позволяет удалить или добавить баллы пользователю")
public HttpStatus changePoints(...) {
	... ... ...
}
Пример помеченного контроллера

Запускаем приложение и открываем Swagger. Видим, что появилась кнопка Authorize. Нажмем на нее и получим возможность установить JWT токен для всех методов. Защищенные методы, которые мы пометили, будут отмечены значком замка.

Устанавливаем токен, после чего нажимаем кнопку Authorize. Переходим к защищенному эндпойнту и вызываем его.

Видим, что Swagger проставил заголовок Authorization, а также сам добавил Bearer к токену. То что нам и было нужно.

Авторизация с использованием Ouath2

😺

Ветка в репозитории: swagger-oauth2

С Oauth2 все оказалось сложнее. Проблема в том, что при авторизации с использованием Oauth2 SpringBoot генерирует JSESSIONID куку, которую сохраняет в браузере. Дальше браузер передает эту куку с каждым запросом, что позволяет SpringBoot приложению понимать кто с ним общается.

Swagger же при Oauth2 авторизации генерирует себе access token, который пытается использовать при запросе. Проблема в том, что он никак не может сам получить значение JSESSIONID, так как его генерирует Spring после успешной Oauth2 авторизации.

Если вы знаете, как решить эту проблему, пожалуйста напишите в комментариях. Я рабочего решения быстро найти не смог.

Поэтому для Ouath2 воспользуемся возможностью сваггера передавать куку.

@OpenAPIDefinition(...)
@SecurityScheme(
        name = "jsessionid",
        in = SecuritySchemeIn.COOKIE,
        type = SecuritySchemeType.APIKEY,
        paramName = "JSESSIONID"
)
public class OpenApiConfig {

}

Помечаем эндпойнты аннотацией:

@SecurityRequirement(name = "jsessionid")

Далее переходим по какому-нибудь урлу нашего API, видим Oauth2 окно авторизации. Проходим авторизацию. Теперь открываем консоль разработчика в браузере и находим раздел с куками.

Вместо настоящего Oauth2 сервера можно использовать mock-server. Который принимает любой email и любой пароль. Удобно использовать при локальной разработке. Конфигурацию подключения можно посмотреть в моей заметке.

Нас интересует кука JSESSIONID, берем ее и вставляем в окно авторизации в Swagger.

Вот и все. Это будет работать.

Итог

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

Документация по API является неотъемлемой частью разработки программного обеспечения. Это руководство по эксплуатации, в котором объясняется, как использовать API и его сервисы. Это руководство может содержать учебные пособия, примеры кода, скриншоты и все остальное, что поможет пользователям лучше понять, как работать с API.

В этой статье мы узнаем, как документировать API, написанный на Node.js используя инструмент под названием Swagger. Swagger позволяет вам описывать структуру ваших API-интерфейсов таким образом, чтобы машины могли их читать. Способность API описывать свою собственную структуру является корнем всего удивительного в Swagger. Почему это так здорово? Что ж, ознакомившись со структурой нашего API, swagger может автоматически создавать красивую и интерактивную документацию по API. Он также может автоматически генерировать клиентские библиотеки для вашего API на многих языках и исследовать другие возможности, такие как автоматическое тестирование. Swagger делает это, запрашивая наш API вернуть YAML или JSON, содержащий подробное описание всего вашего API. Этот файл, по сути, представляет собой список ресурсов нашего API, который соответствует спецификациям Open API.

Создание нашего API с помощью Node.js и Express

Чтобы начать писать спецификации API, мы создадим наш API с Node.js который представляет собой back-end выполнения JavaScript, которая работает на движке JavaScript V8 и выполняет код JavaScript вне веб-браузера. Для простоты мы настроили проект, и его можно клонировать из этого репозитория GitHub. Чтобы запустить серверную часть на вашем локальном компьютере, мы выполним следующие действия:

  • Создайте новую папку для проекта и запустите эту команду в корневой папке, чтобы клонировать репозиторий
git clone https://github.com/DesmondSanctity/node-js-swagger.git
  • Для успешного запуска кода нам потребуется подключение к базе данных. Мы использовали кластер MongoDB Atlas для базы данных, и мы можем следовать этому руководству, чтобы настроить его, это довольно просто настроить. После настройки мы получим наш URL-адрес, и это все, что нам нужно для подключения к нашей базе данных из нашего приложения.
  • Мы используем JSON Web Token (JWT) для аутентификации доступа к нашему API, поэтому мы создадим секретный ключ, который будет использоваться нашим приложением для отправки и проверки запросов. Чтобы сгенерировать это, мы запустим эту команду в любом месте нашего терминала. Этот скрипт сгенерирует случайную 64-битную строку ASCII, которую можно использовать для шифрования токенов JWT.
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
  • Теперь мы создадим файл с именем .env, в котором мы будем хранить URL-адрес нашего кластера MongoDB Atlas и секрет JWT в качестве переменной среды. Файл должен выглядеть так:
    JWT_SECRET=<your JWT secret>
    ATLAS_URI=<your MongoDB Atlas cluster URL>
  • Теперь мы готовы запустить приложение, но сначала мы установим несколько пакетов, а затем запустим приложение. Если вы ранее клонировали репозиторий GitHub, вам просто нужно выполнить следующие команды:
    npm install   // To install the neccessary packages
    npm start    //  To start the application
  • Если вы добились успеха на этом этапе, вы увидите следующее сообщение в своем терминале.
    > mini-blog@1.0.0 start
    > nodemon server.js

    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node server.js`
    Database Connected
    Server connected to http://localhost:8080

Добавление пользовательского интерфейса и конфигураций Swagger

Теперь, когда у нас есть готовый API, мы начнем определять для них спецификации Swagger. Есть два способа создать документацию Swagger для нашего API:

  • Вручную напишите спецификации в файлах маршрутизатора или в специальном файле json или yaml в нашем приложении.
  • Использование существующих инструментов или пакетов разработчика для автоматического создания документации.

В этом руководстве мы будем использовать ручной подход, чтобы обеспечить точность наших определений и спецификаций. Сначала мы установим два пакета под названием «swagger-jsdoc» и «swagger-ui-express» в качестве зависимостей, используя эту команду:

npm install swagger-jsdoc swagger-ui-express --save-dev

После установки мы создадим новый файл с именем swagger.js в корневом каталоге нашего приложения и вставим в него следующий код.

    import swaggerJsdoc from 'swagger-jsdoc'
    import swaggerUi from 'swagger-ui-express'
    const options = {
      definition: {
        openapi: '3.0.0',
        info: {
          title: 'Mini Blog API',
          description: "API endpoints for a mini blog services documented on swagger",
          contact: {
            name: "Desmond Obisi",
            email: "info@miniblog.com",
            url: "https://github.com/DesmondSanctity/node-js-swagger"
          },
          version: '1.0.0',
        },
        servers: [
          {
            url: "http://localhost:8080/",
            description: "Local server"
          },
          {
            url: "<your live url here>",
            description: "Live server"
          },
        ]
      },
      // looks for configuration in specified directories
      apis: ['./router/*.js'],
    }
    const swaggerSpec = swaggerJsdoc(options)
    function swaggerDocs(app, port) {
      // Swagger Page
      app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
      // Documentation in JSON format
      app.get('/docs.json', (req, res) => {
        res.setHeader('Content-Type', 'application/json')
        res.send(swaggerSpec)
      })
    }
    export default swaggerDocs

Из кода, в котором мы определили спецификацию Open API (OAS), которую мы будем использовать для нашей документации, мы можем видеть: информацию или подробности об API, серверах, которым мы будем его предоставлять, и маршрутах в нашем приложении, где Swagger должен искать для спецификаций для каждого из наших API.

Мы также можем видеть нашу функцию swaggerDocs, которая позволяет экземпляру приложения и порту создавать документацию для использования пакетов swaggerUi и swaggerJsdoc, которые мы установили ранее, и обслуживать их по маршруту /docs. Мы также можем получить формат JSON, используя /docs.json. Наконец, мы обновим наш файл server.js, чтобы включить нашу функцию swaggerDocs, чтобы всегда генерировать и обновлять наши документы всякий раз, когда мы запускаем проект.

Последним шагом перед написанием спецификации для каждой конечной точки является добавление функции swaggerDocs в наш файл server.js, чтобы мы инициировали swagger при каждом запуске нашего приложения.

    import express from 'express';
    import cors from 'cors';
    import morgan from 'morgan';
    import dotenv from 'dotenv';
    import connect from './database/conn.js';
    import userRouter from './router/user.js';
    import postRouter from './router/post.js';
    import swaggerDocs from './swagger.js'

    dotenv.config()
    const app = express();
    /** middlewares */
    app.use(express.json());
    app.use(cors());
    app.use(morgan('tiny'));
    app.disable('x-powered-by'); // less hackers know about our stack

    const port = process.env.PORT || 8080;
    /** HTTP GET Request */
    app.get('/', (req, res) => {
        res.status(201).json("Home GET Request");
    });

    /** api routes */
    app.use('/api/user', userRouter)
    app.use('/api/post', postRouter)
    /** start server only when we have valid connection */
    connect().then(() => {
        try {
            app.listen(port, () => {
                console.log(`Server connected to http://localhost:${port}`);
            })
            swaggerDocs(app, port)
        } catch (error) {
            console.log('Cannot connect to the server')
        }
    }).catch(error => {
        console.log("Invalid database connection...!");
    })

Написание спецификаций API

Теперь перейдем к основной задаче: напишем спецификации для нашего API, которые Swagger будет использовать для создания документации для нас. В настоящее время у нас есть два контроллера и файлы маршрутизатора в нашем приложении для user и post. Наши контроллеры содержат логику для приложения, в то время как маршрутизатор передает конечную точку и полезную нагрузку контроллеру в виде запросов. Приступим к определению спецификации!

Для User маршрутизатора мы сначала импортируем необходимые пакеты в файл маршрутизатора user.js:

    import { Router } from "express";
    const userRouter = Router();
    /** import all controllers */
    import * as controller from '../controllers/userController.js';
    import Auth from '../middleware/auth.js';

    /** All the API routes comes here*/

    export default userRouter;

Затем мы напишем спецификацию для каждого типа запроса, а именно GET, POST, PUT и DELETE. Спецификация представляет собой файл yaml, встроенный в начало маршрута, который мы хотим задокументировать. Некоторые ключевые моменты, на которые следует обратить внимание:

  • Экземпляр спецификации Open API — записывается в начале файла yaml.
  • Конечная точка API — URL-адрес, который мы будем использовать для запроса.
  • Request Type — указывает, является ли это запросом GET, POST, PUT или DELETE.
  • Request Body — для передачи нашей полезной нагрузки в API.
  • Parameters — данные, которые мы передаем через URL или параметры в серверную часть.
  • Content Type — тип контента, который мы отправляем. Он передается в заголовок HTTP.
  • Schema — содержит тип нашего тела запроса, обязательные поля и свойства, которые может принимать тело запроса.
  • Response — результат сделанного нами вызова API, он сообщает нам, был ли он неудачным или успешным, а также сообщает об ошибках.

POST:

    /** POST Methods */
    /**
     * @openapi
     * '/api/user/register':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Create a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - email
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe 
     *              email:
     *                type: string
     *                default: johndoe@mail.com
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/register').post(controller.register); // register user

    /**
     * @openapi
     * '/api/user/login':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Login as a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/login').post(controller.verifyUser,controller.login); // login in app

    /**
     * @openapi
     * '/api/user/verify':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Verify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        desccription: Server Error
     */
    userRouter.route('/verify').post(controller.verifyUser, (req, res) => res.end()); // authenticate user

GET:

    /** GET Methods */
    /**
     * @openapi
     * '/api/user/{username}':
     *  get:
     *     tags:
     *     - User Controller
     *     summary: Get a user by username
     *     parameters:
     *      - name: username
     *        in: path
     *        description: The username of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Fetched Successfully
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:username').get(controller.getUser) // user with username

PUT:

/** PUT Methods */
    /**
     * @openapi
     * '/api/user/update':
     *  put:
     *     tags:
     *     - User Controller
     *     summary: Modify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - userId
     *            properties:
     *              userId:
     *                type: string
     *                default: ''
     *              firstName:
     *                type: string
     *                default: ''
     *              lastName:
     *                type: string
     *                default: ''
     *     responses:
     *      200:
     *        description: Modified
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/update').put(controller.updateUser); // is use to update the user profile

DELETE:

/** DELETE Methods */
    /**
     * @openapi
     * '/api/user/{userId}':
     *  delete:
     *     tags:
     *     - User Controller
     *     summary: Delete user by Id
     *     parameters:
     *      - name: userId
     *        in: path
     *        description: The unique Id of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Removed
     *      400:
     *        description: Bad request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:userId').delete(controller.deleteUser);

Тестирование наших API на Swagger

После завершения нашей документации API мы сможем просмотреть нашу документацию Swagger и протестировать наш API, используя ее. Если вы дошли до этого момента, у вас должно получиться изображение, подобное приведенному ниже. Наша документация обслуживается по маршруту /docs.

Мы сделаем несколько запросов, используя пользовательский интерфейс документации Swagger, и посмотрим на результаты.

Чтобы создать User:

Чтобы создать Post:

Как мы видели из приведенных выше примеров, мы можем использовать документацию Swagger для тестирования нашего API, для создания, чтения и изменения данных в нашей базе данных. Это помогает сделать API понятным и простым для интеграции другими. Следуя этим примерам, мы можем пойти дальше и протестировать другие методы запроса, такие как PUT для обновления пользователя или сообщения, GET для чтения пользователя или POST и DELETE для их удаления из базы данных.

Выводы

Наконец, мы можем сделать вывод, что документация по API является очень важной частью цикла разработки программного обеспечения, способствует совместной работе и упрощает взаимодействие с пользователем. Некоторые из преимуществ Swagger включают, но не ограничиваются:

  • Синхронизирует документацию API с сервером и клиентом в одном темпе.
  • Позволяет нам создавать документацию REST API и взаимодействовать с REST API. Взаимодействие с REST API с помощью Swagger UI Framework дает четкое представление о том, как API реагирует на параметры.
  • Предоставляет ответы в формате JSON и XML.
  • Имеются реализации для различных технологий.

Понравилась статья? Поделить с друзьями:
  • Что такое творческий стиль руководства
  • Руководство аппаратом министерства
  • Ретинорм витамины для глаз инструкция по применению цена отзывы аналоги
  • Монтаж стропил вальмовой крыши пошаговая инструкция
  • Компания пэк руководство телефон