BFF

BFF νŒ¨ν„΄μ΄λž€, Backend From Frontend 의 μ•½μžλ‘œ ν”„λ‘ νŠΈμ—”λ“œλ₯Ό μœ„ν•œ λ°±μ—”λ“œμ„œλ²„λ₯Ό κ΅¬μΆ•ν•˜λŠ” λ””μžμΈ νŒ¨ν„΄μ„ λ§ν•œλ‹€.

기쑴의 ν΄λΌμ΄μ–ΈνŠΈ-μ„œλ²„κ°„ API ν†΅μ‹ μ˜ 단점을 꼽으라면 (ν”„λ‘ νŠΈμ—”λ“œ μž…μž₯μ—μ„œ) ν•„μš”ν•˜μ§€ μ•Šμ€ λ°μ΄ν„°λ“€κΉŒμ§€ 응닡에 ν¬ν•¨λ˜μ–΄ μΆ”κ°€μ μœΌλ‘œ 데이터λ₯Ό κ°€κ³΅ν•˜λŠ” λ‘œμ§μ„ μž‘μ„±ν•΄μ•Όν•œλ‹€λŠ” 점이닀.

λ¬Όλ‘ , ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ ν•„μš”ν•œ λ°μ΄ν„°λ“€λ§Œ μ‘λ‹΅ν•˜λŠ” APIλ₯Ό λ§Œλ“€μˆ˜λŠ” μžˆλ‹€. ν•˜μ§€λ§Œ ν΄λΌμ΄μ–ΈνŠΈμ˜ μ’…λ₯˜ (Web, ios, android...)κ°€ λ‹€μ–‘ν•΄μ Έ 같은 ν™”λ©΄μ—μ„œ μ‘λ‹΅λ°›μ•„μ•Όν•˜λŠ” λ°μ΄ν„°μ˜ μ’…λ₯˜μ— 맞좰 APIλ₯Ό κ°œλ°œν•˜λŠ”κ²ƒμ€ λΉ„νš¨μœ¨μ μΌλΏλ”λŸ¬, λ³΅μž‘ν•œ 데이터 κ°€κ³΅λ‘œμ§μ„ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ‹€λ£°κ²½μš°, λ Œλ”λ§ λ¬Έμ œκ°€ λ°œμƒν• μˆ˜λ„ μžˆλ‹€.

이런 배경속에 κ³ μ•ˆλœ νŒ¨ν„΄μ΄ λ°”λ‘œ BFF νŒ¨ν„΄μ΄λ‹€.

μ‰½κ²Œ 말해, ν΄λΌμ΄μ–ΈνŠΈ-μ„œλ²„ 의 κ΄€κ³„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈ - BFF μ„œλ²„ - μ„œλ²„μ˜ κ΄€κ³„λ‘œ ν†΅μ‹ ν•˜λŠ” 것이닀.

μœ„μ—μ„œλ§ν–ˆλ“―μ΄, BFF μ„œλ²„λŠ” ν”„λ‘ νŠΈμ—”λ“œλ₯Ό μœ„ν•΄ μ‘΄μž¬ν•˜λŠ” μ„œλ²„μ΄λ‹€. 즉, ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ‹€λ€˜λ˜ 데이터 κ°€κ³΅λ‘œμ§μ„ BFF μ„œλ²„μ—μ„œ μ²˜λ¦¬ν•΄ ν•„μš”ν•œ λ°μ΄ν„°λ§Œ μ‘λ‹΅ν• μˆ˜ μžˆλ‹€. μžμ—°μŠ€λ ˆ ν΄λΌμ΄μ–ΈνŠΈ 둜직과 API λ‘œμ§μ„ λΆ„λ¦¬ν• μˆ˜ 있으며, ν΄λΌμ΄μ–ΈνŠΈμ˜ 뢀담을 μƒλ‹Ήμˆ˜ 쀄여쀄 μˆ˜μžˆλ‹€. μ΄λŸ¬ν•œ 점은 μ™ΈλΆ€ APIλ₯Ό μ‚¬μš©ν•΄μ•Ό ν• λ•Œ λ”μš± νš¨μœ¨μ μ΄λ‹€.

interface AIResponse {
  id: string
  object: string
  created: number
  model: string
  choices: Array<{
    index: number
    message: {
      role: string
      content: string
    }
    finish_reason: string
  }>
  usage?: {
    prompt_tokens: number
    completion_tokens: number
    total_tokens: number
  }
}

μœ„ μΈν„°νŽ˜μ΄μŠ€λŠ” Open AI API의 응닡객체이닀. κ°„λ‹¨ν•œ 챗봇을 λ§Œλ“ λ‹€κ³  μƒκ°ν•΄λ³΄μž. μœ„ μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ •μ˜ν•œ ν”„λ‘œνΌν‹°λ“€μ΄ λͺ¨λ‘ ν•„μš”ν• κΉŒ? λ‹Ήμ—°νžˆ μ•„λ‹ˆλ‹€. μ‹€μ§ˆμ μœΌλ‘œ ν•„μš”ν•œ 뢀뢄은

interface AIResponse {
  choices: Array<{
    index: number
    message: {
      role: string
      content: string
    }
    finish_reason: string
  }>
}

이 뢀뢄이닀. μ’€ 더 μ •ν™•νžˆ λ§ν•˜λ©΄ choice λ°°μ—΄μ˜ μ›μ†Œμ˜ message.content 뢀뢄일 것이닀. λ”°λΌμ„œ

const getAiResponse = async() => {
    const res: Promise<AIResponse> = await axios.get(ENDPOINT,{ prompt })
    const contentArray = res.choices.map(choice => choice.message.content);
    return contentArray;
}

μ΄λŸ°μ‹μœΌλ‘œ 응닡객체λ₯Ό κ°€κ³΅ν•˜λŠ” 둜직이 ν¬ν•¨λ˜μ–΄μ•Ό ν•œλ‹€. μ§€κΈˆμ€ 맀우 κ°„λ‹¨ν•œ μ˜ˆμ‹œμ§€λ§Œ, 닀뀄야할 데이터가 많고 λ³΅μž‘ν•΄μ§„λ‹€λ©΄ 둜직이 길어짐에 따라 ν•¨μˆ˜λ„ κΈΈμ–΄μ§€κΈ° λ•Œλ¬Έμ— λ‘œμ§μ„ λͺ¨λ“ˆν™”ν•΄ λ‹€μ‹œ ν˜ΈμΆœν•˜λŠ” λ“± 번거둜운 과정을 κ±°μ³μ•Όν•œλ‹€. BFFλ₯Ό μ μš©ν•΄λ³΄μž

// route.ts
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const { prompt } = req.body;
    const aiRes = await axios.post<AIResponse>(ENDPOINT, { prompt });
    const contentArray = aiRes.data.choices.map(choice => choice.message.content);
    res.status(200).json({ content: contentArray });
  } catch (error) {
    console.error('Error fetching AI response:', error);
    res.status(500).json({ error: 'Failed to fetch AI response' });
  }
}
// sample.tsx

const fetchAiResponse = async (prompt: string) => {
  try {
    const res = await axios.post('/api/ai-response', { prompt });
    return res.data.content;
  } catch (error) {
    console.error('Error fetching AI response:', error);
    return null;
  }
};

λ‘œμ§λΆ„λ¦¬λ‘œ 인해 μ½”λ“œκ°€ 맀우 깔끔해진것을 볼수 μžˆλ‹€. μ˜ˆμ‹œμ— μ‚¬μš©ν•œ Next js의 API κΈ°λŠ₯이 λ°”λ‘œ λŒ€ν‘œμ μΈ BFF νŒ¨ν„΄μ˜ μ˜ˆμ‹œμ΄λ‹€. μ˜ˆμ‹œμ—λŠ” μ—†μ§€λ§Œ μ€‘μš”ν•œ 인증 킀값같은 데이터도 ν΄λΌμ΄μ–ΈνŠΈκ°€ μ•„λ‹Œ BFF μ„œλ²„μ—μ„œ 닀루기 λ•Œλ¬Έμ— λ³΄μ•ˆμ„±λ„ μš°μˆ˜ν•˜λ©°, ν΄λΌμ΄μ–ΈνŠΈ κ°œλ°œμ‹œ ν”νžˆ λ§ˆμ£ΌμΉ˜λŠ” CORS 도 ν”Όν• μˆ˜ μžˆλ‹€.

CORS λŠ” ν΄λΌμ΄μ–ΈνŠΈκ°€ λ‹€λ₯Έ 도메인에 접근을 μ‹œλ„ν•˜λ € ν• λ•Œ λ°œμƒν•œλ‹€.

그런데 BFF μ„œλ²„λŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ 같은 도메인을 κ°€μ§€κ³  있으며, BFF μ„œλ²„ - μ„œλ²„ 톡신은 μ„œλ²„μΈ‘μ΄κΈ° λ•Œλ¬Έμ— CORS κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€..!

Last updated