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

Идея паттерна Backend-For-Frontend пришла от разработчиков программного обеспечения из SoundCloud. Фил Кальсадо (один из создателей) дал архитектурное объяснение узору, так что вы можете пойти взглянуть здесь.

Почему паттерн BFF?

Давайте воспользуемся ситуацией.

Предположим, вы создаете приложение для фирмы по недвижимости, которое позволяет пользователям просматривать недвижимость на продажу и, возможно, записывать встречи или что-то в этом роде.

Шаблон получения данных таков (при условии, что вы используете шаблон MVC):

Получить свойства из базы данных - ›Модель сериализует данные -› Контроллер выполняет любую необходимую логику - ›Данные передаются для просмотра

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

Более современный подход состоит в том, чтобы сделать серверную часть ресурсом API с простым в использовании выводом (например, JSON), а затем позволить команде внешнего интерфейса просто сосредоточиться на использовании вывода данных API, достигнув определенных конечных точек.

Очень упрощенная модель такого подхода описана ниже:

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

Эта проблема

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

Во-первых, что, если бы у вас было мобильное приложение, которое должно использовать тот же API, но не такой же результат, как веб-приложение? Возьмем, к примеру, приложение "Недвижимость".

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

Второе ограничение: что, если мы решим сделать API общедоступным? Вот пример общедоступного API SoundCloud, в котором SoundCloud дает что-то особенное, чтобы дать пользователям своего веб-сайта то, чего не предлагал общедоступный API. Имея центральный API для каждого интерфейса, у нас нет простого способа определить, какую функцию предоставить какому потребителю API.

Чтобы решить эту проблему, в игру вступил паттерн Backend-For-Frontend.

Давай сделаем несколько лучших друзей

Идея проста - создать бэкэнд для каждого внешнего интерфейса.

У вас есть веб-приложение, которое хочет использовать основной API? Создайте серверную часть специально для веб-интерфейса.

У вас есть интерфейс Android / iOS, которому нужен основной API? Создайте бэкэнд для внешнего интерфейса Android / iOS.

А затем создайте основной исходный код API и сохраните его в отдельном независимом пространстве.

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

В примере с недвижимостью предположим, что мы хотим войти в систему через Интернет, но для основной серверной части мы должны использовать аутентификацию API. Мы воспользуемся преимуществами сеансов Laravel для хранения токенов и использования их в качестве заголовка аутентификации.

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

Основной внутренний домен: http: //main-backend.test

Веб-домен внешнего интерфейса: http: //web-frontend.test

Внутренний веб-домен (наш BFF): http: //backend.web-frontend.test

Мы будем использовать Passport для аутентификации (проверьте эту ссылку, чтобы получить краткое руководство по Laravel Passport).

Код входа хранится в основном коде серверной части (http: //main-backend.test). Это проиллюстрировано ниже:

То, что там произошло, просто:

  • Создать методы для рассылки ответов; вывод - JSON
  • В методе входа в систему извлеките данные запроса [на этом этапе вы можете выполнить любую проверку]
  • Аутентифицируйте полученные данные с помощью Auth Facade, предоставляемого Laravel, убедитесь, что данные отражены в модели пользователя и таблице «пользователи». В противном случае укажите.
  • Вернуть успешный ответ с правильными деталями, в противном случае - ответ об ошибке.

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

Для аутентификации с помощью кода BFF (размещенного по адресу http: //backend.web-frontend.test) приведенный ниже код может находиться в файле маршрута BFF:

Как видите, пакет GuzzleHttpLaravel используется для отправки HTTP-запроса на ваш основной внутренний сервер.

Если вы можете вспомнить (или вернуться, чтобы проверить), ваш основной бэкэнд возвращает вывод JSON с двумя частями информации; токен и пользовательские данные. Жетон здесь очень важен. После успешной проверки на внутреннем сервере он отправляет успешный ответ вашему BFF, который затем переходит в блок else (поскольку ответ не является ошибочным ()). Затем токен извлекается и передается в ваш веб-сеанс, и на ваше представление http: //web-frontend.test создается ответ.

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

Скажем, это код для получения свойств из базы данных, хранящейся на нашем основном внутреннем сервере, http: //main-backend.test

Как видите, ресурс защищен промежуточным программным обеспечением auth / api, что означает, что мы не получаем никаких данных без аутентификации API. Давайте покажем наш токен API и получим данные из исходного кода BFF:

Маршрут:

Контроллер:

Это должно подвести итог всем моим пунктам. Из приведенного выше фрагмента кода я сделал HTTP-запрос, используя методы withHeaders и withToken для установки заголовка и токена API соответственно. Теперь он может получить доступ к ресурсу API и получить список данных. (Узнайте больше о выполнении запросов Laravel Http здесь)

Зачем все это проходить?

Что ж, как я упоминал ранее, он снимает ограничения, которые накладывает связанный прямой API. Благодаря этому у вас есть возможность контролировать, как любой клиент взаимодействует с вашим API. Вы можете сделать часть своих сервисов общедоступными, а свои особые данные и функции оставить при себе. Вы можете настроить свой мобильный и веб-интерфейс на свой вкус. Все зависит от вас и вашего интерфейса Backend-For-Frontend. Вы можете создать аналогичный BFF для своего интерфейса Android. И еще один для вашего интерфейса iOS.

И тогда ваш основной API не будет беспокоить торги своих потребителей.

Полезно: ознакомьтесь с Mohamed Said, чтобы получить полезные советы по бэкенду.