Explyt Spring Plugin — наша версия HTTP-клиента для IntelliJ IDEA

Всем привет! Как следует из названия статьи, речь пойдет о HTTP-клиентах для IntelliJ IDEA. Да, опять). В последнее время было несколько публикаций на эту тему, и мы бы хотели подробно рассказать о нашем взгляде на эту проблему и нашей реализации. А также поговорить о плюсах и минусах текущих решений для IDEA. Ранее мы уже рассказывали о нашем плагине для Spring — о том как у нас реализована поддержка Dependency Injection в частности, теперь настала очередь HTTP client’а.

Проблема

Как известно, в IDEA Ultimate «был» отдельный плагин HTTP Client, который предоставлял кастомный DSL (Domain Specific Language) для написания HTTP запросов и имел свой механизм для их исполнения. В настоящее время также стали появляться похожие инструменты от других разработчиков плагинов для IDEA. Все они так или иначе основаны на подобном подходе — создании кастомного DSL. Рассмотрим более подробно плюсы и минусы такого подхода. Как и в любом решении, здесь есть компромиссы: то, что даёт нам гибкость, одновременно требует дополнительных усилий.

Плюсы:

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

  • соответственно, мы можем реализовывать практически любые фичи, как на уровне DSL, так и на уровне интеграции с IDE;

  • теоретически кастомный DSL можно рассматривать отдельно от IDEA и использовать в девопс практиках и в тестировании, как это произошло, например, с DSL от IDEA Ultimate.

Минусы:

  • реализовывать свой DSL — это достаточно трудоёмкое занятие;

  • пользователю нужно во все это погружаться — учить новый «мини» язык и разбираться, как это работает;

  • также нужно реализовывать поддержку в IDE, как на уровне редактора, так и на уровне работы с выходными данными запроса — UI.

Наш взгляд на эту проблему

В нашем плагине мы уже умели генерировать OpenApi файлы для Spring Controllers (кнопка Run напротив имени класса) и далее открывать Swagger UI в IDEA для созданных файлов.

076c678d16e3e529dbdd5cb81f93c7ea.pngИнформация об этом есть на Wiki Explyt Spring

Информация об этом есть на Wiki Explyt Spring

Созданные файлы в таком виде могли использоваться для получения OpenApi документации по проекту прямо из IDEA без запуска проекта и для возможности протестировать приложение локально через сваггер. Но для последнего пункта, нужно чтобы приложение было запущено локально, а эту проблему можно решить, просто добавив в зависимости проекта спринг-стартер: springdoc-openapi-starter-webmvc-ui и в целом для тестирования текущего приложения это было не очень полезно.

Но нам пришла в голову идея -, а почему бы не сделать из этого механизма свой HTTP клиент на минималках, который можно применять для вызова внешних сервисов, используя OpenApi, Swagger UI и аннотации Spring Web в качестве DSL для написания запросов. Это может быть полезно, когда есть задача по интеграции с каким нибудь сторонним HTTP сервисом. И хочется сначала «пощупать» его на примерах, сделав тестовые обращения к нему, чтобы понять как оно работает и какой результат возвращает.

Более подробно по шагам это процесс можно представить вот так:

  • с помощью хорошо знакомых Spring Web аннотаций пользователь на любом удобном ему языке Java\Kotlin описывает REST метод;

  • генерируем OpenApi схему, на основании написанного метода;

  • запускаем Swagger UI прямо в IDEA по файлу из предыдущего пункта;

  • и далее пользователь в уже хорошо знакомом ему инструменте, с готовым UI, сможет выполнять HTTP запросы.

Плюсы:

  • не надо делать свой UI —  используем Swagger UI;

  • не надо делать свой DSL — используем Spring Web Annotations & OpenApi;

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

  • относительная простая реализация.

Минусы:

  • решение менее гибкое и менее расширяемое, т.к используем уже готовые компоненты. Соответственно имеем только то что имеем и кастомизировать это очень трудно.

  • узкоспециализированное решение для Spring (требует Spring Web в зависимостях, но в планах есть добавить поддержку JAX-RS, чтобы быть более платформо-независимыми)

  • нельзя строить сложные сценарии, состоящие из последовательности  запросов, когда один вызов, является отправной точкой для другого;

  • используемые решения тоже не лишены недостатков и имеют свои проблемы (например CORS в Swagger UI).

Как это работает

Чтобы лучше понять, что получилось и как этим пользоваться, рассмотрим это на примере интеграции с одним из сервисов погоды — https://api.openweathermap.org

Допустим мы хотим проверить что возвращает нам сервис -https://api.openweathermap.org/data/2.5/weather.

Для этого просто возьмем и создадим метод на основе Spring аннотаций. Заметим что реализация этого метода нам не важна, как в целом и возвращаемый тип. Т.к. HTTP это текстовый протокол, то в качестве выходного типа можно указать строку или вообще ничего не указывать и оставить void. Swagger UI сам, на основании заголовков ответа, сможет понять, как отобразить результат запроса, в самом общем случае это просто текст.

25af8ad9967e13d2ba2939762858d712.png

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

Если нажать на него, то откроется хорошо знакомый всем Swagger UI:

a4ce967b91fe883f2ef7e7a30e3c339f.png

Где мы через интерфейс Swagger UI сможем выполнить запрос:

e22aec103f43fe93fd013acf13808491.png

Также тут мы сразу получаем запрос в curl формате и можем это использовать, чтобы выполнить его через командную строку или как-то его модифицировать, сохранив себе в блокнотик. После выполнения запроса, получаем результат:

399ad452026bd0187809e3d848f9f2fc.png

Т.к. наши генераторы OpenApi файлов по коду, могут отличатся от оригинальных и давать другой результат, то вы всегда можете отредактировать OpenApi вручную, если чувствуете в себе силы или завести баг. Чтобы перейти в режим редактирования, можно нажать «переключалку» вверху справа в окне Swagger. Кстати для OpenApi файлов, мы поддерживаем различные подсказки и авто-дополнения, так что редактирование OpenApi — это на самом деле не так страшно, как может показаться). 

fbc64b0022d0195741b5e43f6e882f5c.png

Также если у нас несколько сервисов, имеют общий URL, то такие методы можно сгруппировать в классы:

4e086f99036ce79eaeb795905806894e.png

Если мы используем Kotlin, то можем создавать тестовые HTTP методы прямо в Kotlin файле, минуя создание лишних классов, в результате это будет выглядеть почти как Ultimate HTTP Client):

6eb56d1eec1e334fcb92b9f3519131aa.png

Если вы используете Feign для создания клиента, то в таком случае, можно сразу попробовать вызвать удаленный сервис:

b88220e6cd424b9933b0069c5f8107fe.png

Для обычных Spring контроллеров, мы генерируем OpenApi файл с тегом servers: localhost:8080, чтобы пользователь смог протестировать свое приложение локально, хотя это не совсем актуальный кейс как мы писали в начале статьи, или сможет сам указать нужный host в теге server OpenApi файла, чтобы проверить как работает сервис например на тестовом контуре.

Благодаря тому что мы используем Swagger UI, нам не пришлось делать свой интерфейс для работы с результатами запросов. Вот так например, выглядит HTTP запрос который скачивает наш плагин с GitHub:

ad36d7bdf05357b808fe7123d45aca13.png9104555491d7d12cf8753ec49af72d77.png

Вот так выглядит результат, если пытаемся загрузить картинку:

303300ea91e7ddcd3dd5be7765713dd4.png

Генераторы кода

Чтобы меньше «набирать» код, мы сделали удобные генераторы, для создания Spring Web методов прямо из Url или Curl (тут опять может пригодиться Curl запрос, который генерирует Swagger). Данные функции доступны из меню Alt+Insert или (Command ⌘)+N на Mac, когда мы находимся внутри Java класса или Kotlin файла:

ae0883be65373c59ac0b4adf47810f48.png

Результат:

7c23fac059ca7b151454788be7f7a453.png

Или вариант с Curl:

d41152afe2f15e7b740ea0dcfe67efe9.png60534f0ce08ac593059fb4a8aa521f61.png

Многие пользователи для тестирования HTTP запросов предпочитают создавать обычные методы, где используя привычный им HTTP клиент, непосредственно в Java/Kotlin пишут код для вызова сервиса. Для таких случаев мы также поддержали конвертация из Url/Curl сразу в java.net.http.HttpClient в меню Alt+Insert это опция «HttpClient method». Вызвав которую для примера выше, получим код:

3728d8e6f62a18393873fb91f2d2dd1c.png

По итогу у нас есть следующие конверторы (генераторы кода):

Проблемы и детали реализации

IntelliJ IDEA включает в себя Embedded Browser (Java Chromium Embedded Framework — JCEF). Поэтому с тем чтобы запустить Swagger UI прямо в IDE не возникло никаких проблем. Просто добавили Standalone Swagger UI в ресурсы плагина и используем его как превью-генератор для OpenApi файлов. Посмотреть детали нашей реализации можно в репозитории на GitHub — OpenApiCefBrowser.

Но возникла другая проблема, связанная с тем, что мы выполняем веб запросы из браузера — это CORS. Кстати, на эту тему есть хорошая статья на Habr. Чтобы обойти эту проблему, пришлось написать свой request handler. Для JCEF клиента мы можем задать свой обработчик запросов. Где делегируем исполнение запросов Java HttpClient, а результат отдаем в браузер. Детали реализации можно посмотреть опять же в нашем репозитории.

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

9a1ce0f9beaa6ccd133b5bf468aa650f.png

Для более удобной работы с «эндпоинтами» мы доработали наше Explyt Endpoints Tool Window. Где постарались улучшить дизайн и отображаем все возможные URL’ы что нашли в проекте и предоставляем навигацию к ним, а также поиск и фильтрацию. Если там чего то не хватает на ваш взгляд, то можете смело заводить issue на доработку, мы всегда рады обратной связи и предложениям.

Заключение

Мы постарались упростить процесс тестирования Rest API, надеемся так оно и вышло. Также мы продолжаем работать над нашими генераторами схем OpenAPi по коду проекта, чтобы сделать их лучше. Скачать последнюю версию плагина с HTTP клиентом можно тут или напрямую с GitHub Releases.

Приглашаем вас попробовать наш плагин, а также делиться своими отзывами и предложениями. Ваша обратная связь поможет нам сделать инструмент более полезным и удобным. Также напоминаем, что плагин имеет открытый исходный код, который доступен на GitHub.

Будем благодарны за ваши вопросы и идеи: GitHub Issues, Telegram-чат, а также личные сообщения в нашем профиле на Habr.

© Habrahabr.ru