GUI для отладки HTTP запросов (webhook tester)

    "Много инструментов для отладки не бывает!" - подумал топикстартер, выполняя в терминале go mod init и предвкушая более чем тривиальный, но тем не менее любопытный пет-проект.

    Как показывает собственный опыт - если разработчик пишет код, который взаимодействует с внешним миром, то закон Мерфи сработает быстрее, чем хотел бы того этот самый разработчик. И дело даже не в том, что в этом случае появляются зависимости от доступности внешнего мира и стороны принимающей данные - часто ошибки появляются на стороне кода отправляющего данные из-за недостаточной его проверки, полагаясь на "ну, код вроде выглядит нормально, да и unit-тест есть на это". Но должного ли качества этот самый тест, и фиксирует ли он то, что надо? А что будет, если состав данных будет совсем не такой, как в тесте?

    В этот момент появляется желание посмотреть "так что же на самом деле отправляет my-awesome-lib?", и если это желание возникает и у тебя, мой дорогой читатель, и отправка происходит посредством протокола HTTP - то, возможно, у меня для тебя есть "ещё одна тулзовина для отладки HTTP запросов" в твою коллекцию.

    Предыстория проекта

    Разумеется что такие штуки уже есть в сети, например - webhook.site (MIT, self-hosted/premium cloud versions), webhookapp.com (cloud only), requestbin.com (cloud only). Но почти всё, что попадалось на глаза - требовало регистрации, редко что можно было запустить "у себя" (да и внешний вид не очень радовал глаз).

    Разумеется, что потребность в таком инструменте у меня возникла довольно остро и в самый неожиданный момент. Нужно было быстро что-то поднять и отдать своей команде в пользование, так как именно в тот момент реализовывали модуль внешней интеграции по HTTP, и его нужно было отлаживать перед боем. Тогда выбор остановился на проекте webhook.site, и в процессе его поднятия "у себя" было выявлено несколько неприятных моментов, а именно:

    • Проект написан на PHP (ничего не имею против PHP, он всё ещё довольно динамично развивается, и для ряда задач он является просто отличным инструментом), но его применимость именно для такого проекта вызывает некоторые вопросы

    • Необходимость в 3rd party solutions для уведомлений браузера о том, что произошло событие в приложении ("пришел" новый запрос и его необходимо отобразить) силами pusher.com или laravel-echo-server

    • Необходимость в nginx + php-fpm для обслуживания HTTP запросов несколько усложняют его быстрый запуск, так как контейнеры нужно между собой связать да в нужном порядке запустить, а потом ещё и мониторить их

    • Неудобство в настройке (субъективно)

    • Суммарный вес всех необходимых образов и потребляемые ими CPU + RAM вызывали некоторую печаль

    Но не смотря на все эти недостатки - проект выглядел очень удачным! Спустя довольно короткое время после его успешного запуска и был выполнен в терминале go mod init , после чего томными вечерами в любимой IDE появлялась имплементация этого-же проекта, включающая весь базовый функционал но уже на Go + Vue.js со стороны front-end.

    Особенности реализации

    В этой части поста я хотел бы поделиться мыслями относительно подходов, что были применены в этом простом проекте. Скорее всего, их понимание будет затруднено отсутствием возможности их обсуждения "как на code-review ветки с фичей", но я постараюсь донести основные мысли (если в комментариях вы выскажете свои веские и аргументированные замечания по их поводу - я буду чертовски признателен).

    InMemory имплементации внешних зависимостей. Если есть какая-либо служба, от которой зависит работоспособность приложения - очень желательно иметь её "альтернативный" вариант, который работает только с памятью "внутри" вашего приложения. Например - хранилище данных имеет имплементацию что пишет и читает данные в Redis, и рядом с ней - что использует только память. Декларативное качество хранилища при использовании 1+N (N >= 1) имплементаций возрастает в разы, тестирование становится простым и понятным, и в unit-тестах когда нам нужно передать "что-то, что умеет читать или писать в хранилище" - мы смело "подсовываем" нашу inmemory имплементацию. Более того, реализация работы inmemory выступает в роли спецификации "что мы вообще хотим от хранилища", и у нас появляется приятный бонус при запуске приложения в режиме single-node (не кластере, а именно в единичном экземпляре) - не надо поднимать никакие дополнительные зависимости, всё есть "из коробки". Естественно что это не всегда применимо (особенно когда от хранения требуются сложные транзакции), но если возможность реализации inmemory имеется - вы вряд ли пожалеете что потратили на неё своё время.

    HTTP пробы /live, /ready ; /metrics в формате prometheus. Они должны быть всегда, если ваше приложение умеет в HTTP (а если не умеет - то подумайте о том, чтоб научить). /live может всегда возвращать 200 код, что означает "я запустился, но могу ли обрабатывать трафик - не знаю", /ready же возвращает 200 код только тогда, когда хэндлер этой пробы убедится в доступности всех зависимых служб (СУБД, exchanges, etc), что означает "я всё проверил и смогу обрабатывать трафик". Про метрики уточнять, думаю, не требуется - они должны быть всегда, хотя бы просто данные рантайма. Классным подходом ещё можно считать возможность запуска сервера pprof на отдельном порту, если приложение запускается, например, с флагом --debug, но в этом проекте этого не реализовывал (возможно сделаю позже). Запускать пробы и метрики на отдельном порту или "основном" - тема дискуссионная (считаю что лучше на отдельном, но для этого проекта этим пренебрёг).

    Docker образ, основанный на scratch(distroless). От образа мы хотим наше приложение, а не дистрибутив Linux, в который оно доставлено. Это не только малый вес итогового образа, но и "однозначность" окружения, от которого зависит работа нашего приложения. Да, у вас не будет возможности где-то на проде выполнить docker exec -ti container-hash sh и "поковыряться" там, но если у вас такие необходимости возникают то, возможно, вы делаете что-то не так. И так же не забывайте использовать не привилегированного пользователя, где это только только возможно.

    Конфиги. Ох, сколько же копий сломано сторонниками кланов "только флаги", "только файлы", "только внешние хранилища" в междоусобных войнах.. Для себя вывод сделан следующий - "делай так, как надо тебе сейчас и в чуть-чуть обозримой перспективе". Сперва всё делается на флагах, если их не хватает - то те штуки что флагами описывать сложно - переезжают в конфиг; и только когда ops-товарищи попросят что-то придумать для управления ими отдельно от манифестов деплоя - тогда выносить куда-то. Так как этот сервис простой и настройки с использованием флагов достаточно - всё сделано при их помощи (значения флагов всегда могут быть перекрыты переменными окружения).

    Front-end на Vue.js без необходимости в сборщике. Так как не являюсь front-end разработчиком от слова совсем, но очень хочется "реактивности" и компонентного подхода - был использован http-vue-loader - он позволяет очень быстро и просто, не вникая в то "как, чем, и с какими конфигами собирать фронты" получить всю силу Vue прямо в браузере. Это кажется каким-то безумием, что браузер сам загружает .vue файлы и их успешно использует. Применимо это, естественно, только для совсем небольших SPA проектов, и здесь он в очередной раз пришелся как никогда кстати. В устаревших браузерах он работать будет вряд ли, но их ниша крайне мала, поэтому ими пренебрёг.

    Обслуживаем WebSocket соединения самостоятельно. Так как это первый проект, где вебсоветы были имплементированы с обоих сторон самостоятельно - полученное удовольствие описать сложно. Для этого проекта не требуется ни pusher, ни socket.io - весь функционал есть "из коробки".

    Как им пользоваться?

    Для начала, его необходимо запустить:

    $ docker run --rm -p 8080:8080/tcp tarampampam/webhook-tester:X.X.X serve

    В качестве X.X.X укажите версию приложения (тег docker-образа), полный список которых можно найти по этой ссылке.

    После этого нужно открыть в браузере http://127.0.0.1:8080/ и вуа-ля! Для вас уже создана сессия и вы можете отправлять HTTP запросы по уникальной ссылке для того, чтоб визуально посмотреть "а что там было фактически отправлено":

    Другими словами - если у вас есть некоторый участок кода, который должен обращаться по HTTP к 3rd-party сервису, то укажите в качестве точки обращения к этому сервису полученный URL из приложения, и запускайте свой код.

    Вы можете кастомизировать контент ответа и HTTP код по своему усмотрению (он может быть указан и в URL запроса - порою это удобнее чем пересоздавать сессии). Можете выставить и задержку ответа, тем самым имитируя сетевые задержки, и смотреть как ваш код на них реагирует "на самом деле" (не падает ли по таймауту, и корректно ли его обрабатывает).

    Если захотите запустить его в нескольких экземплярах за балансировщиком нагрузки - вам понадобится Redis сервер (укажите storage и pubsub драйверы redis), конфигурация подробно описана в readme файле проекта.

    Docker-образ с приложением весит (в сжатом виде) всего ~4.4 Mb, а само приложение очень аскетично к потребляемым ресурсам.

    Все детали всегда могут быть найдены в репозитории проекта - tarampampam/webhook-tester, а поиграться с демо можно тут - web.hook.sh.

    Вместо заключения

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

    Если вы найдете какие-то ошибки или недостающий функционал - просто создайте issue в репозитории с ним (используя английский язык, пожалуйста). При наличии возможности обязательно внесу необходимые изменения.

    Отдельное спасибо товарищу под ником fredsted за его webhook.site - "делать так-же" было значительно проще, чем придумывать идею с нуля.

    top secret

    Если вы видите этот текст, то это означает что его автор открыт для предложений по работе в роли TeamLead/Golang-разработчика на постоянной основе. Если вам нравится ход моих мыслей и код, то на Хабре есть личные сообщения, вы знаете что делать :)

    UPD: НЛО перенесло этот пост из хаба "Я пиарюсь" в хабы "Разработка веб-сайтов, Go, Управление разработкой"

    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 13

      –1
      отправка происходит по средствам протокола

      поэтично, но грамотность явно хромает
        +1

        виноват, недоглядел, исправил. если найдёте ещё что-то — пишите в ЛС, пожалуйста

        –2

        Я что-то не понимаю. plain http читается чем попало. Записать tcpdump и любоваться из wireshark'а, а во многих случаях достаточно глазками в выводе на экран того же tcpdump'а.


        Чтение TLS значительно сложнее и требует ключей. Но зачем писать ещё один веб-интерфейс в стиле wireshark, да ещё без возможнсотей самого wireshark?

          +2

          Сравнивать wireshark и этот проект как сравнивать осциллограф с простеньким мультиметром — вторым можно воспользоваться "быстро и наглядно", в то время как первым исследовать детально :) И при помощи wireshark вряд ли можно заставить некоторый порт по запросу определенного URI "отвечать" определенным ответом

            0

            "Заставить отвечать" — это либо http replay (если нам надо побайтно), либо (на уровне языка) всякие vcr/betacam'ы и их порты на другие языки.

            +2
            Не ради холивара, но для TLS я поднимаю mitmproxy и успешно наблюдаю за запросами и ответами.
              0

              Это и есть "требует ключей". У вас либо недоверенные сертификаты (которые не всегда можно подсунуть софту), либо есть доступ к серверному ключу. Есть ещё третий вариант — это запускать на машине, которой свой CA доверен и подписывает что попало. Но: Это не работает с софтом у которого certificate pinning, и разные рантаймы могут использовать разные списки CA (тот же python, java). Всё преодолеваемое, но геморройно.


              А ещё, что обидно, иногда нужно видеть трафик с оригинальным сервером, а не с прокси (потому что, например, странно заголовки обрабатываются).

            +1
            А есть то же самое, только без докеров и прочих штук? То есть, чтобы можно было бы установить просто как движок сайта.
              +3
              Держите. Только вам наверно будет полезно знать, что докер как раз помогает вам не заморачиваться с тем как этот «движек» запустить, ведь движек нужно поместить еще в машину, подключить залить масло и прочее.
              0

              Класс! Будем пользоваться.


              Может кто-то подскажет? Есть такая ситуация:
              Отправляем в рамках автотестов хук, надо чтоб служба приняла его и ответила об успехе или ошибке.
              Как можно это реализовать? Какие-то существуют инструменты? Может есть какие-то практики?

                0

                Для автотестов обычно пишутся отдельные моки для зависимых сервисов (в рамках тестов или отдельные сервисы). Ещё можно взять что-то вроде mmock (ничего самому писать не надо, только настроить) — и он будет отвечать нужным пейлоадом по определенному запросу. Это то, что вы искали?

                  0

                  Большое спасибо за наводку!

                  +1
                  Если чисто проверить реквест, и данных не важны, попробуйте mockery.dev

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

                Самое читаемое