2026.02.04. 17:52
1. 문제 인식
개발환경이 전환되는 등 상황에서 계속적으로 api 상태가 불안정하다.
그리고 SSR과 CSR이 혼재가 되어있는 상황에서 API 요청의 baseURL이 이원화되는 문제가 있어 관리가 어렵다.
-> 어떤 API가 CSR에서 요청되는지, SSR에서 요청되는지를 분류해야한다.
초기에는 집에서만 개발하는 것을 상정했으나 점차적으로 다른 컴퓨터 등에서 시연하거나 개발해야하는 경우를 염두에 두지 않을 수 없고
추후 유지보수성을 고려했을 때 전체적으로 리팩토링이 필요한 상황이다.
구체적인 문제점
백엔드로 가야하는 API 요청이 자꾸 프론트 루트로 감. 이 문제가 정확히 nginx 문제인지, 환경변수 문제인지 알아내기 어려운 부분이 있음.
이원화된 베이스url 관리. 지금 SSR요청용 url(컨테이너 url)과 CSR요청용 url(도메인) 등이 이원화 되어있고 어느 로직에 이를 적용해야할지 불분명하거나 수정에 따라 에러가 발생함. -> 유지보수 어려움
nginx 과대화. nginx가 인프라 영역을 넘어 게이트웨이 역할+라우팅을 하다보니 로직이 혼재되고 커짐. 환경변수도 과도화됨.
결론
현재 원인은 프론트가 API 게이트웨이 역할을 하지 못하고 nginx가 그 역할을 맡고 있어서 생기는 문제. 즉 어플리케이션 계층에서 API 경로제어를 하지 않고 인프라(nginx) 계층에서 경로제어를 하는 것이 문제.
--> 어플리케이션 계층에서 API 경로제어를 위한 계층을 추가해야함. => BFF 패턴
2. BFF 패턴

모든 요청이 프론트엔드에 부속되어있는 라우트 게이트웨이를 통해 이뤄짐.
=> 인프라 레벨에서의 api 라우팅이 아니라 어플리케이션 계층에서 수정됨.
인프라 계층인 nginx에서는 불필요한 리다이렉션 코드를 유지할 필요없고 프론트에서도 이원화된 코드를 유지할 필요 없음.
3. 구체적인 코드 예시
'use server'
import { jsonApi} from "@/lib/axios";
import { AxiosResponse } from "axios";
export interface SaveCommentReq {
post_id: string
text: string;
}
export interface SaveBlogPostReq {
id?: string | null; // undefined. id가 없으면 -> create / id가 있으면 -> update로
title: string;
page_json: string;
page_html?: string | null;
}
// const res = await fetch(`http://localhost:8089/api/blog/posts/${params.id}`, {
// cache: "no-store", // SSR 목적일 경우
// }); // 별도의 필드 주입이 없으면 get 사용
// //console.log("posts : ",await res.json())
// console.log();
// const post = await res.json();
// //const posts = await res.json();
export interface getPostJsonRes {
id: string;
title: string;
page_json: string;
}
export async function saveBlogPost(
data: SaveBlogPostReq
){
const res = await jsonApi.post('/api/blog/saveblogpost', data);
return { status : res.status }
}
export async function updateBlogPost(
data: SaveBlogPostReq
){
const res = await jsonApi.put('/api/blog/posts', data);
return { status : res.status }
}
export async function deletePost(
id: string
): Promise<number> {
const res = await jsonApi.delete(`/api/blog/posts/${id}`)
return res.status;
}
export async function getPostJson(
id: string
): Promise<getPostJsonRes> {
const res = await jsonApi.get(`/api/blog/posts/getjson/${id}`);
return res.data;
}
export async function SaveComment(
data: SaveCommentReq
): Promise<AxiosResponse> {
return await jsonApi.post(`/api/blog/comment`, data)
}
export async function deleteComment(
id: string
): Promise<AxiosResponse> {
return await jsonApi.delete(`/api/blog/comment/${id}`)
}
export async function getPostCommentsAxios(postId: number): Promise<AxiosResponse> {
return await jsonApi.get(`/api/blog/comments/${postId}`)
}기존 axios 서비스 계층을 use server 처리함.
(장기적으로는 fetch로 이동해야 next에서 제공하는 최적화 등을 받을 수 있음)
이렇게 할 경우 프론트에서 해당 코드를 호출할 경우 자동으로 서버쪽에서 해당 코드가 실행됨.