Паттерны Gateway и Backend-for-Frontend

Gateway — единое окно для разных API. Backend-for-Frontend использует Gateway для обработки запросов и подготовки ответов, предназначенных для фронтенда.

Время чтения: 7 мин

Кратко

Секция статьи "Кратко"

Gateway и Backend-for-Frontend (BFF) — паттерны проектирования для разработки веб-приложений. Оба паттерна используются для обеспечения доступа к разным API с помощью одного контракта. Контракт — это всё то, что позволяет общаться двум сетевым узлам между собой: архитектура построения сетевого соединения, набор сетевых протоколов, набор адресов и портов для доступа к данным, правила формирования запросов со стороны клиентов, механизм подготовки и отправки ответов со стороны сервера.

Как понять

Секция статьи "Как понять"

Современное веб-приложение состоит из интерфейса, с которым работает пользователь, и бэкенда, который пользователь не видит. Бэкенд может быть устроен по-разному, всё зависит от задачи. Бэкенд крупных веб-приложений обычно довольно сложно устроен.

Как правило, бэкенд — это совокупность разных программ (микросервисы) или одна большая программа (монолит). В современном вебе всё чаще используется микросервисный подход, о котором вы можете прочитать в статье «Микросервисы». Проблема такого сложного бэкенда состоит в том, что каждый микросервис предоставляет уникальный программный интерфейс. Фронтенду приходится работать с каждым микросервисом отдельно и помнить API каждого. Это неудобно, создаёт жёсткую связь между фронтендом и бэкендом, требует много знаний о внутреннем устройстве бэкенда. Решение этой проблемы состоит в том, чтобы сделать один унифицированный интерфейс, который в свою очередь будет обращаться ко всем микросервисам.

Общение фронтенда с микросервисами напрямую

Одним из первых таких решений был Gateway, который является, как правило, прокси-сервером и предоставляет единое окно для доступа к данным по определённому программному интерфейсу (Application Programmable Interface — API), пересылая данные от фронтенда к нужному микросервису и обратно. Внешний вид приложения пользователя меняется, бизнес-логика меняется, клиентское приложение меняется, может меняться и контракт, но на остальные API это никак не влияет. Gateway пересылает запросы со стороны клиентов на другие API, учитывая разницу в контрактах, и этим позволяет снизить зацепление бэкенда и фронтенда в веб-приложении. Как правило, на стороне Gateway частые запросы могут кэшироваться, может быть реализована простая бизнес-логика, которая обеспечивает контроль над набором пересылаемых данных между клиентом и внешним API.

Использование Gateway

Работа Backend-for-Frontend, который является развитием идеи единого окна, похожа на Gateway в задачах обеспечения единого контракта и контроля над набором данных. BFF обязательно включает в себя Gateway, к которому предъявляются следующие требования:

  • Общие шаблоны на клиенте и сервере (например, JSX).
  • Высокая скорость ответа под нагрузкой.
  • Единый язык на клиенте и промежуточном сервере BFF.
Использование Backend-for-Frontend

Общие шаблоны очень важны, поскольку это существенно ускоряет разработку и облегчает поддержку как клиентской части приложения, так и серверного приложения BFF. Учитывая, что и язык должен быть единым, это позволяет переиспользовать код на клиенте и сервере. Высокая скорость ответа достигается не только применением кэширования частых запросов, но средствами предварительной подготовки данных для запросов от клиента.

Можно использовать BFF не только для доступа к различным API. Например, паттерн BFF прекрасно ложится на архитектуру построения веб-приложения, в которой на стороне сервера работают микросервисы. Вы можете прочитать о них в статье «Микросервисы».

Как начать

Секция статьи "Как начать"

Если в качестве языка разработки используется JavaScript, то очевидно, что необходимо обеспечить исполнение кода. Скорее всего, вы будете использовать Node.js, но есть и альтернативы: Deno или GraalVM. Node.js прекрасно подходит для большого количества операций ввода/вывода, но не в случае вычислений. Для BFF это отличный выбор.

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

Для BFF прекрасно подходит концепция слоёв. В этой концепции происходит разделение пользовательского интерфейса (в нашем случае API, к которому обращается клиент) от бизнес-логики и данных. Серверное приложение обычно построено на слоях и связях между ними. Есть несколько подходов для реализации слоёв.

Трёхуровневая (трёхзвенная) архитектура — исторически один из первых подходов, который построен на совместной работе трёх слоёв: слоя клиента, слоя бизнес-логики и слоя данных. Нижний слой — слой данных. Он взаимодействует со слоем бизнес-логики, который в свою очередь взаимодействует с клиентским слоем. В трёхуровневой архитектуре клиентский слой изолирован от слоя данных.

Трёхуровневая (трёхзвенная) архитектура

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

Domain-Driven Design (DDD) — более современный подход, когда приложение разбивается на четыре слоя: пользовательский интерфейс (клиент), бизнес-логика, домен, инфраструктура. В этом подходе нижним слоем является слой инфраструктуры, над которым располагается доменный слой (он определяет все сущности необходимые для работы слоя бизнес-логики в рамках доменной области).

Domain-Driven Design (DDD)

Такой подход неплох, но он слишком тяжёлый для BFF. Часто требования к продукту таковы, что определение домена и основной бизнес-логики должно лежать на бэкенде. Задача BFF — быть удобной и лёгкой прослойкой между фронтендом и бэкендом.

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

Чистая архитектура — ещё более современный подход, в котором используются те же четыре слоя, что и в DDD, но иначе. Слой инфраструктуры поднимается до уровня пользовательского интерфейса. Это позволяет избегать протечки абстракции. Домен становится центром приложения. В современных BFF-приложениях используется чистая архитектура.

Чистая архитектура

В качестве фреймворка часто выбирают Express в связке с Nest.js. Безусловно, проектирование конкретного приложения зависит от бизнес-задачи и доменной области веб-приложения. Вы можете почитать о нескольких успешных практиках использования BFF в следующих статьях:

Есть проекты с небольшими BFF, например, этот: