API_PATH или как frontend может узнать, где находится его backend?
Рассказываем, как решить проблему получения пути до бэкэнда пятью разными способами.
7К открытий13К показов
Александр Широчкин
эксперт-разработчик в Группе «Иннотех»
Всем привет!
Эта статья родилась в ответ на многочисленные вопросы начинающих коллег в нашем корпоративном сообществе фронтенд-разработчиков. Пример вопроса от человека, который недавно пришёл на новый проект в «Иннотех»: «Ребята, привет! Подскажите, при сборке и поставке приложения на разные контуры (стенды)переменные окружения прокидываются на этапе CI, или я что-то путаю?»
Сразу оговорюсь, ряду проектов этого не требуется — если бэк стабильно «живёт» на том же URL что и фронт, можно всегда относительно текущего location на всех стендах определить, куда же отправлять запросы на бэк. Но существуют ситуации, когда разработчик не может знать точно, по какому URL будет запущено его web-приложение: например, когда его web-приложение встраивается в другое (распространенные реализации микрофронтендов и виджетов).
В более широком смысле проблема получения пути до бэкэнда может быть представлена как проблема получения конфигурационных параметров фронтендом.
Работая в разных компаниях, я замечал, что многие айтишники — аналитики, devops, бэкэнд-разработчики и даже некоторые фронтенд-разработчики (которые сами эту задачу никогда не решали) — имеют слабое представление об этой проблеме, хотя хотя бы в общем смысле представлять, как работает UI их систем нужно всем. Для тех, кто пока не понимает, о чём речь, поясню достаточно базовую вещь: фронтенд — это, по сути, html, css и js (и прочие, например, шрифты и картинки) статические файлы.
Что значит статические? Это такие файлы, которые не изменяются — скажете вы, и будете правы. Но что ещё немаловажно, эти файлы не исполняются на сервере — просто лежат, а web-сервер отдаёт их вашему браузеру, и вот там уже они и исполняются. А раз файлы на сервере не исполняются, получить параметры окружения (env) они не могут, следовательно, подставить в эти файлы ссылку на бэкэнд нельзя.
Эту задачу можно решить разными путями: обозначу их и попробую разобрать каждый. Для простоты они будут расположены в порядке сложности (хотя это дискуссионный вопрос — имплементация этих путей может отличаться, как и опыт и навыки тех, кто это реализует).
Путь 1.Зашиваем в бандл объект с параметрами всех окружений и уже в зависимости отlocation выбираем путь к API
Вариант реализации: в коде храним объект, который содержит конфигурацию для всех окружений.
Плюсы:
· Простота реализации;
· Не требует помощи devops;
Минусы:
· При изменении конфига любого из контуров (стендов) необходимо обновлять код и пересобирать приложение;
· Изменение исходного кода приложений вместо конфигураций, девопсы и админы не будут рады такому подходу, поэтому возможно будут привлекать разработчиков (а нам то это ни к чему);
· Вытекает из предыдущего. Разработчик становится ответственным за этот участок, требуется его привлечение к релизам (обычно за конфиги приложения отвечают девопсы либо админы).
Путь 2.Организация проксирования web-сервером
Реализация простая — в конфиге web-сервера прописываем маршрут (например location /api/ для nginx) до своего backend. Важный момент — подразумевается, что конфиг вашего веб-сервера не хранится в репозитории проекта, а в рамках вашей CI/CD предусмотрены хранилища параметров под разные стенды.
Плюсы:
· Простота реализации;
Минусы:
· Этот путь решает только конкретную проблему, другие конфиги в приложение данным способом не задать;
· Не все любят возится с конфигурациями nginx.
Путь 3.Модификация собранного кода приложения (бандла)
Его вариации:
1. В коде фронта использовалась переменная вида «%%BACKEND_URL%%», с ней же он собирался, а потом в рамках деплоя это значение в js-файлах собранного билда заменялось на нужный URL
2. Скрипт (например env.js), подключаемый в
Плюсы:
· Простота реализации;
Минусы:
· Неаккуратное изменение способно полностью закрашить ваше приложение (в ряде реализаций);
· Разные хэши одной и той же версии приложения на разных стендах это не вполне хорошо, т.к. разработчик не может на 100% говорить, что тестировал ровно этот же код на другом окружении. Более того, в ряде организаций правилами информационной безопасности это запрещено.
Путь 4.На веб-сервер на этапе деплоя вместе с бандлом frontend-приложения кладётсяфайл с конфигурацией (например /params.json)
Работа frontend-приложения начинается с получения данного параметра. На этом шаге можно предусмотреть резервную схему – если значения в файле нет (либо нет файла), то формировать путь на основе location, либо какого-то дефолтного значения.
Плюсы:
· Баланс простоты реализации и качества решения;
· Приложение не закрашится от некорректного значения;
· Нет претензий со стороны информ.безопасности;
Минусы:
· Кто-то считает это решение намного сложнее предыдущего и не видит между ними принципиальной разницы.
Путь 5.Специальный микросервис конфигов на том же location (с зафиксированнымпортом)
Посадить рядом (на том же url) с фронтом небольшой сервис (можно на NodeJS, а можно и на чём-то другом), который будет читать переменные окружения и отдавать на фронт. Зачастую такой сервис называют BFF (backend for frontend), но передача конфигов не является его единственной функцией.
Можно, конечно, пойти дальше по этому пути и реализовать одну из вариаций Service Discovery. Если кратко, то это сервис, в котором регистрируются другие сервисы, он сообщает о них другим сервисам, также он может контролировать их «живость».
Плюсы:
· Все конфиги читаются из переменных окружения (да хоть из БД);
· Можно навесить дополнительный функционал на данный сервис;
Минусы:
· Сложность реализации (особенно если это поручить фронтендеру, который ни разу не разрабатывал бэк), либо расход ресурсов бэкенд-разработчиков;
· Это может вам не потребоваться (оверинжиниринг).
Личныйопыт
На текущем проекте я занимаюсь разработкой микрофронтендов и мне важно без пересборки приложения (и изменения его исходного кода) иметь возможность залить его на разные стенды. Я использую 4-й путь: при необходимости в девопс-репозиторий с inventory вношу изменения, которые мне нужны в этом файле. Почему я выбрал именно его?
Хранение параметров всех окружений в репозитории моего проекта (1-й путь) посчитал неприемлемым, поскольку поддержка его требовала бы регулярного отвлечения внимания от более важных задач.
Просто организовывать проксирование на веб-сервере (2-й путь) не стал, так как решил заложить на будущее возможность передавать дополнительные параметры конфигурации, а этот вариант для такого не подходит.
К модификации собранных приложений отношусь очень настороженно, поэтому отмёл 3-й путь. Да и безопасникам не хочется лишний раз объяснять, почему код приложения на разных стендах не совпадает.
На одном из прошлых проектов (в другой компании) я использовал 5-й путь, т.к. у нас этот nodeJS минибэк обладал рядом дополнительных функций (отвечал за аутентификацию и авторизацию, работал с файлами – получение, парсинг, формирование отчетов в разном формате).
Желаю всем удачи и найти свой путь!
7К открытий13К показов