BFF (Backend for Frontend)

·

4 דקות קריאה

תמונת כותרת עבור BFF (Backend for Frontend)

אמ;לק

ארכיטקטורת Backend-for-Frontend (או BFF) היא לא רק דרך ״לפרמט״ תשובות JSON עבור המובייל. היא דפוס ארכיטקטוני שהופך “Public Client״ לא מאובטח (כמו הדפדפן) ל-”Confidential Client״ מוקשח. בפוסט הזה נלמד למה ה-BFF הוא קריטילאבטחת טוקנים (Goodbye, LocalStorage), איך הוא מונע Over-fetching, ומדוע פריימוורקים מודרניים כמו Next.js הם למעשה BFF במסווה.

הרקע: הבעיה עם “One Size Fits All”

דמיינו את הסיטואציה הבאה (אני בטוח שחלקכם חוויתם אותה בפרויקט צד או בעבודה): בניתם בקאנד חזק ב-Go או Node.js. הוא חושף API גנרי ומקיף. עכשיו הצוות בונה אפליקציית Web, אפליקציית IOS, ואולי אפילו אינטגרציה לשעון חכם.

הבעיה? דפדפן דסקטופ רץ על חיבור סיב אופטי יציב ויכול להציג טבלאות ענק. השעון החכם? יש לו מעבד חלש ורשת סלולרית מקרטעת. אם שניהם פונים לאותו Endpoint גנרי שמחזיר אובייקט של 5MB, הרגתם את חווית המשתמש במובייל.

יתרה מכך, והרבה יותר חמור: איפה אתם שומרים את ה-Access Token שלכם ב-Web? אם התשובה היא localStorage, יש לנו בעיית אבטחה. כאן ה-BFF נכנס לתמונה

איך זה עובד: הארכיטקטורה

בבסיסו, ה-BFF הוא שכבת תווך (Facade) ייעודית לחוויות משתמש ספציפית. במקום API אחד לכולם, יש לנו שרת ייעודי לאפליקציית המובייל ושרת ייעודי לאפליקציית ה-Web.

אבל בואו נצלול לעומק ה-”Deep Tech” של הסיבה האמיתית לאמץ BFF: אבטחה.

בעולם ה-OAuth 2.0, אפליקציית SPA (כמו ריאקט או אנגולר) נחשבות Public Clients. הן רצות בסביבה לא בטוחה (הדפדפן של המשתמש). אי אפשר לשמור שם סודות. כל מה שנמצא בקוד צד-לקוח חשוב להתקפות XSS (Cross-Site Scripting).

ה-BFF משמש כ-Confidential Client. הוא רץ על השרתים שלכם.

  1. הפרונטאנד (הדפדפן) מזדהה מול ה-BFF באמצעות HttpOnly Cookie (שמוגן מפני גישת Javascript).

  2. ה-BFF מחזיק את ה-Tokens הרגישים (API Keys, OAuth Tokens) בזיכרון או ב-Session Store מאובטח בצד השרת.

  3. ה-BFF פונה ל-Microservices האחרים (“Downstream Services”) ומזריק את הטוקנים הנדרשים לבקשה.

התוצאה? אפס טוקנים רגישים מסתובבים בדפדפן. שטח התקיפה הצטמצם משמעותית.

קוד: ה-BFF המודרני

אחת התובנות המפתיעות היא שרבים מכם כבר משתמשים ב-BFF בלי לקרוא לו כך. פריימוורקים כמו Next.js, Remix, או SvelteKit הם למעשה Integrated BFF.

הנה דוגמה לאיך זה נראה ב-Next.js (App Router). שימו לב איך אנחנו משתמשים ב-Route Handler כדי להסתיר מידע ולסנן שדות מיותרים:

// app/api/user-dashboard/route.ts
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

// This acts as our BFF layer
export async function GET() {
  // 1. Security: Get the session ID from a secure, HttpOnly cookie
  const cookieStore = cookies();
  const sessionId = cookieStore.get('secure_session_id')?.value;

  if (!sessionId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // 2. Downstream Call: Fetch heavy data from the core Microservice
  // The actual API Key is stored safely on the server environment
  const upstreamResponse = await fetch('https://api.internal.corp/heavy-user-data', {
    headers: {
      'Authorization': `Bearer ${process.env.CORE_SERVICE_API_KEY}`,
      'X-Session-ID': sessionId
    }
  });

  const heavyData = await upstreamResponse.json();

  // 3. Transformation: The "Frontend" part of BFF
  // Instead of sending 50 fields, we send exactly what the UI needs
  const optimizedPayload = {
    displayName: `${heavyData.firstName} ${heavyData.lastName}`,
    avatar: heavyData.profileImages['thumbnail_200px'], // Logic tailored for UI
    pendingTasks: heavyData.tasks.filter((t: any) => t.status === 'URGENT').length
  };

  return NextResponse.json(optimizedPayload);
}

מה קרה כאן?

  1. Security Boundary: ה-API key הפנימי (process.env.CORE_SERVICE_API_KEY) לעולם לא נחשף לקליינט.

  2. Payload Optimization: במקום לשלוח אובייקט ענק עם היסטוריית לוגים ותמונות ברזולוציה גבוהה, שלחנו JSON רזה ומדויק לקומפוננטה.

ניתוח: לא הכל ורוד (Trade-offs)

כמו כל ארכיטקטורה טובה, יש כאן מחיר.

  1. ה-Fan-Out Problem: כשה-BFF שלכם צריך לפנות ל-5 סרוויסים שונים כדי להרכיב מסך אחד, אתם בבעיה. אם סרוויס אחד איטי, כל הבקשה איטית. אם סרוויס אחד נופל ללא טיפול שגיאות נכון, כל המסך קורס.

    1. הפתרון: שימוש ב-Circuit Breakers (כמו הגישה של Netflix Hystrix בעבר) ומימוש אגרסיבי של Caching בתוך שכבת ה-BFF.
  2. תחזוקה וכפילות: אם יש לכם BFF למובייל ו-BFF ל-Web, סביר להניח שתכתבו לוגיקה עסקית דומה פעמיים.

    1. הפתרון: ספריות משותפות (Shared Libraries) או שימוש בגישות כמו GraphQL (או כלים כמו WunderGraph) שמאפשרים לייצר BFF-ים באופן דקלרטיבי יותר, שם ה״קוד״ הוא למעשה שאילתה שנבנית בזמן Build.
  3. מתי זה יותר מדי? בחברות ענק (כמו נטפליקס), ריבוי BFF-ים הופך לסיוט תחזוקתי. שם העולם מתקדם ל-Federated Supergraphs (כמו Apollo Federation), שמאפשרים לצוותים שונים לנהל חלקים שונים בגרף המידע, אבל זה נושא לפוסט נפרד לחלוטין.

סיכום

ה-BFF הוא שלב התבגרות קריטי בפיתוח מערכות. הוא המקום שבו אנחנו מפסיקים להתייחס ל-Backend כ״מחסן נתונים״ ומתחילים להייחס אליו כאל שותף פעיל בחוויית המשתמש ובאבטח המידע. אם אתם בונים מערכת שצריכה לשרת גם Web וגם Mobile, אם אם אתם עוסקים במידע רגיש - ה-BFF הוא לא המלצה, הוא סטנדרט.

הצעד הבא שלכם

בדקו את פרויקט הצד שלכם. האם אתם חושפים את מבנה ה-Database שלכם ישירות ל-UI? האם הטוקנים שלכם חשופים ב-Local Storage? אולי הגיעה הזמן להרים שכבת ביניים קטנה וחכמה.