Backend for Frontend (BFF) — это подход, при котором создаётся отдельный слой серверной логики для конкретного фронтенд-приложения. Он служит посредником между клиентом и множеством микросервисов, упрощая интеграцию и оптимизацию данных под нужды конкретного интерфейса. В контексте Fresh, фреймворка на базе Deno, BFF реализуется с использованием роутинга, middleware и серверных обработчиков, позволяя создавать высокопроизводительные приложения с минимальной задержкой.
В Fresh маршруты создаются через файловую систему. Каждый файл в
директории routes/ соответствует отдельному URL. Для BFF
важно структурировать маршруты так, чтобы они отражали логику
фронтенда, а не внутренние сервисы:
// routes/api/user.ts
import { HandlerContext } from "$fresh/server.ts";
export const handler = async (req: Request, ctx: HandlerContext) => {
const response = await fetch("https://internal-service.example.com/users");
const data = await response.json();
return new Response(JSON.stringify({
id: data.id,
name: data.name,
email: data.email
}), {
headers: { "Content-Type": "application/json" },
});
};
Ключевой момент: BFF агрегирует данные и возвращает клиенту только нужный набор полей, снижая нагрузку на фронтенд и уменьшая количество HTTP-запросов.
Fresh поддерживает middleware через handlers и функции
верхнего уровня в маршрутах. Для BFF это важно для:
Пример middleware для проверки токена:
// routes/api/_middleware.ts
import { HandlerContext } from "$fresh/server.ts";
export const handler = async (req: Request, ctx: HandlerContext) => {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token || token !== Deno.env.get("API_KEY")) {
return new Response("Unauthorized", { status: 401 });
}
return ctx.next();
};
Использование middleware позволяет централизовать логику безопасности, не дублируя её в каждом маршруте.
BFF позволяет объединять ответы нескольких микросервисов в один:
// routes/api/dashboard.ts
export const handler = async (req: Request) => {
const [userRes, ordersRes] = await Promise.all([
fetch("https://internal-service.example.com/users/123"),
fetch("https://internal-service.example.com/orders?userId=123")
]);
const user = await userRes.json();
const orders = await ordersRes.json();
return new Response(JSON.stringify({
user: { id: user.id, name: user.name },
orders: orders.map(o => ({ id: o.id, total: o.total })),
}), { headers: { "Content-Type": "application/json" } });
};
Этот подход уменьшает число HTTP-запросов с клиента, повышает скорость загрузки страниц и упрощает фронтенд-код.
Fresh и Deno позволяют использовать встроенные возможности для ускорения BFF:
Пример кэширования с использованием caches:
const cache = await caches.open("bff-cache");
const cachedResponse = await cache.match(req.url);
if (cachedResponse) return cachedResponse;
// получение данных от сервисов
const response = await fetch("https://internal-service.example.com/data");
const clonedResponse = response.clone();
cache.put(req.url, clonedResponse);
return response;
Ключевой эффект — уменьшение нагрузки на внутренние сервисы и ускорение отклика.
BFF должен корректно обрабатывать ошибки микросервисов, не передавая фронтенду «сырые» исключения:
try {
const res = await fetch("https://internal-service.example.com/users");
if (!res.ok) throw new Error("Service unavailable");
const data = await res.json();
return new Response(JSON.stringify(data));
} catch (err) {
return new Response(JSON.stringify({ error: err.message }), {
status: 502,
headers: { "Content-Type": "application/json" },
});
}
Такой подход обеспечивает стабильность фронтенда, даже если один из внутренних сервисов недоступен.
На стороне Fresh BFF взаимодействует с компонентами через
fetch внутри useEffect или серверные
функции. Преимущество в том, что фронтенд получает
готовые, адаптированные под UI данные, без лишней
логики:
/** @jsx h */
import { h } from "preact";
export default function UserProfile({ data }) {
return (
<div>
<h1>{data.user.name}</h1>
<ul>
{data.orders.map(order => (
<li key={order.id}>Order #{order.id}: {order.total}</li>
))}
</ul>
</div>
);
}
BFF скрывает сложность микросервисов и предоставляет фронтенду чистый, структурированный API.
BFF используется не только для внутренних микросервисов, но и для внешних API, обеспечивая:
Пример:
const response = await fetch("https://api.example.com/weather");
const data = await response.json();
return new Response(JSON.stringify({
temperature: data.temp,
condition: data.weather[0].main
}));
Такой слой облегчает поддержку и масштабирование интеграций с внешними сервисами.
BFF в Fresh — это комбинация файлового роутинга, middleware, серверной агрегации и кэширования, ориентированная на потребности фронтенда. Он упрощает управление данными, повышает производительность и обеспечивает стабильность пользовательского интерфейса. Правильная организация BFF позволяет строить масштабируемые и легко поддерживаемые приложения на Deno с минимальными накладными затратами.