
1. FE개발에 모킹이 필요한 이유와 방안
1. 왜 모킹이 필요할까?
신규 서비스를 시작하는게 아니라면 보통은 백엔드에 이미 구축된 데이터베이스와 api명세가 작성되어있어, 프론트엔드 개발자는 작성된 명세대로 개발하면 될 것이다. 하지만 프론트엔드와 백엔드가 같은 시점에 개발을 시작하면 프론트엔드 개발자 입장에선 백엔드의 DB구축과 api개발을 기다려야 하는 상황이 생긴다.
위 상황이 왜 문제인가?
- 서비스 출시 일정이 지연된다.
- UI 개발과 데이터 로직을 분리하기 어렵다.
- 프론트엔드 로직의 품질이 낮아질 수 있다.
- 팀 간 협업 효율이 떨어진다.
2. FE Mocking 방법
위 단점들을 해결하기 위해선 FE에서도 실제로 api를 사용하는것 처럼 연출하는 상황이 필요하다. 방법은 정말 다양한데, 가장 간단한 방법으로는 api가 아닌 mock 데이터를 상수처럼 정의해서 사용하는 방법과 끝까지 간다면 실제로 FE api서버를 직접 구축해서 운용하는 방법이 있다.
json-server 활용
간단한 JSON 파일 하나로 실제 REST API와 유사하게 동작하는 로컬 서버를 빠르게 구축할 수 있고, POST, PUT, DELETE 등의 HTTP 메서드도 지원하여 실제 API를 사용하는 듯한 경험을 할 수 있다.
MSW (Mock Service Worker) 사용
서비스 워커를 이용해 네트워크 요청을 가로채서 모의 응답을 반환하므로, 애플리케이션의 API 요청 코드를 전혀 수정하지 않고도 모킹이 가하다. 실제와 정말 유사한 이점 있음.
Postman 등 API 테스트 도구 활용
Postman과 같은 도구의 모킹 기능을 사용하면, API 명세만으로 실제처럼 동작하는 URL을 생성하여 팀원들과 공유할 수 있다.
AWS Serverless 활용
실제 백엔드와 가장 유사한 환경을 클라우드에 직접 구축하여 API를 개발하고 테스트할 수 있다. 이를 통해 복잡한 로직이나 데이터베이스 연동까지 미리 구현하며 안정적으로 개발을 이어갈 수 있다.
직접 서버 운영
실제 express 같은 서버를 띄워서 백엔드에서 하는 작업을 동일하게 구현하고 사용할 수 있다.
2. 프론트엔드 API 발전과정
개발 초창기에는 mock데이터를 활용하는 방식으로 운영했었다. 사실 가장 간단한 방법이다. 컴포넌트를 mock데이터로 채워두고, 백엔드의 api가 완성될때, fetching과 기타 처리를 하면 되는 방식이다. 충남대 2팀 FE에서도 3주차 까지는 작성되어있는 테크스펙대로 mock데이터들을 작성하여 각자의 컴포넌트를 설계하기로 했었다.
src/__mocks__ 경로에 아래처럼 이미지 폴더와 mock.ts 파일들을 정의해서 export하면 되는 방식이다.

import squidgameSpotdetail from './images/squidgame-spotdetail.jpg';
import squidgameSpotdetail2 from './images/squidgame-spotdetail2.jpg';
export const contentScenes = [
{
id: 1,
title: '무궁화 꽃이 피었습니다',
description:
'456명의 참가자들이 참여한 첫 번째 게임. 어린 시절 추억의 놀이가 생과 사를 가르는 잔혹한 게임으로 변했다.',
image: squidgameSpotdetail,
episode: '1화',
timestamp: '32:15',
},
{
id: 2,
title: '설탕 뽑기',
description:
'달고나에서 모양을 온전히 뽑아내야 하는 두 번째 게임. 단순해 보이지만 가장 어려운 게임 중 하나.',
image: squidgameSpotdetail2,
episode: '3화',
timestamp: '15:30',
},
...
1. 발전된 모델, 서버리스 api를 도입하다
도입 배경
- 우리 팀은 개발 0주차부터 CI/CD 배포라인을 구축해두었고, dev 서버와 main 서버를 운영 중이다. 따라서 json-server처럼 로컬 환경에서만 테스트하는 방식보다는 실제 배포 환경에서 검증할 수 있는 테스트 환경이 필요했다.
- 백엔드에서 제공하기 어려운 API가 생겼을 때, 프론트엔드에서 서버리스 API(AWS Lambda, API Gateway)를 활용하면 대응할 수 있다.
- Lambda는 사용량 기반 과금 구조이기 때문에, 테스트나 보조용 API 운영 시 비용 효율적이다.
- 컴포넌트를 개발하면서 추가적으로 필요하거나 불필요해진 데이터를 서버리스 API로 유연하게 관리하면, 백엔드와의 API 형식을 맞추어 나가며 점진적으로 통합하기에 용이하다.
- API Gateway를 통해 인증, 로깅, 버전 관리 등을 간단히 적용할 수 있어 유지보수성과 확장성이 높다.
lambda와 api gateway를 활용한 초기 구성

글을 쓰고 있는 지금도 백엔드와 계속 api에 대해 논의중에 있다. 지금까진 내가 요청한 데이터를 내려줄 수 있다고 확답을 듣고 있어서, 내가 설계할 아키텍처는 실 서비스에서 사용할 용도가 아닌 mock api로만 활용해도 될듯해서, 가장 간단하게 설계하였다.
Mock데이터 운영 방식
백엔드에서 최대한 데이터를 지원해준다고 했으니, 굳이 DB까지 운용할 필요는 없다고 생각했다. 따라서 lambda함수 내부에 json 배열을 정의하고, 그 데이터를 바로 내려주는 방식을 사용하도록 하였다. 예를들어, itinerary(동선) 도메인에서 사용될 여러 장소 데이터들을 저장해두고, 그 장소들의 순서를 랜덤 조합하여 mock 동선을 생성해주는 방식을 사용중이다.
mock_locations = {
101: {
"locationId": 101, "name": "더현대 서울", "address": "서울 영등포구 여의대로 108", "latitude": 37.5258, "longitude": 126.9285,
"description": "MZ세대의 성지로 불리는 서울의 대표적인 백화점입니다.",
"locationImage" : "https://github.com/Jaeho-Site/mock-test-images/...",
"relatedContents": [{"contentId": 4, "title": "BTS", "category": "POP"},{"contentId": 5, "title": "오징어게임", "category": "DRAMA"}]
},
102: {
"locationId": 102, "name": "소피텔 앰배서더 서울", "address": "서울 송파구 잠실로 209", "latitude": 37.5126, "longitude": 127.1025,
"description": "석촌호수 전망의 5성급 럭셔리 호텔입니다.",
"locationImage" : "https://github.com/Jaeho-Site/mock-test-images/...",
"relatedContents": [{"contentId": 4, "title": "BTS", "category": "POP"},{"contentId": 5, "title": "오징어게임", "category": "DRAMA"}]
}, //more locations ...이미지에 대한 처리
이미지는 보통 db에 직접 저장하지 않는다. 스토리지에 저장하고 CDN에 캐싱한 후 url을 저장하는 방식으로 운영된다. 현재 우리 백엔드에선 이미지를 db에 직접 저장하고 있지만, AWS 인프라를 사용한다면 S3에 저장하고 Cloudfront에 캐싱해두는 방식을 사용하도록 요청해둔 상태이다. 하지만 FE 테크리더인 내가 BE 작업까지 강제할 수는 없으므로 방법을 구상하는 중에 있다.
지금은 백엔드와 통합전 mock데이터로만 운영하는 형태이므로, 스토리지에 저장하지도 않았고, github에 이미지들을 올려두고, 이미지 주소를 받아와서 사용하는 중이다.
RESTful 하게 api 내려주기
우리팀은 rest api를 사용하고 있고, 이에 맞추어 api gateway에서 rest를 생성해 주었다. 스프린트 초기 까진 GET요청에 대한 처리만 해주면 되었으므로, GET메소드만 생성해서 운영하였다. 기본적으로 contents도메인에선 /contents 로 호출시 인기 데이터 순으로 뿌려주고, /contents?category=drama 이렇게 파라미터로 카테고리를 지정하면 카테고리별 인기 순위를 받아올 수 있다.
아래 코드는 /locations 도메인에 대한 예시 코드이다.
def lambda_handler(event, context):
http_method = event.get('httpMethod')
path_parameters = event.get('pathParameters') or {}
location_id = path_parameters.get('id')
if http_method == 'GET':
if location_id:
# GET /locations/{id}
location = mock_locations.get(int(location_id))
if location:
return create_response(200, "장소 상세 조회 성공", location)
else:
return create_response(404, "해당 장소를 찾을 수 없습니다.", error_code="NOT_FOUND_LOCATION")
else:
# GET /locations
return create_response(200, "장소 전체 목록 조회 성공", list(mock_locations.values()))
return create_response(405, f"지원하지 않는 메서드입니다: {http_method}", error_code="METHOD_NOT_ALLOWED")
2. BE에 의존적이지 않은 FE 아키텍처 구축

1. 우아하게 보안 및 비용 최적화하기
AS IS
만약 팀 개발자가 로직을 잘못 구현해서 api를 반복 호출되게 한다면, 악의적인 유저가 api를 계속 호출한다면, 사용량에 따라 발생하는 비용대로 클라우드 비용이 청구될 것이다.
만약 api gateway를 cloudfront에 캐싱해도, 여전히 api gateway를 통해서도 호출이 가능했었다. api gateway의 스테이지 경로를 유출하지 않으면 상관없지만, 개발자로서 단일 api경로만 호출가능하도록 엔지니어링을 하고 싶었다.

TO BE
우선 CloudFront 캐싱을 통해 백엔드 호출을 최소화하고, 직접 호출 경로를 차단하여 예기치 않은 비용 급증을 원천적으로 방지하였다. (사실 이부분도 AS-IS)
하지만 이렇게 해두어도 결국 api gateway에 대한 접근이 열려있어서 위 예시 문제 상황 캡쳐처럼 직접 접근이 가능했었다.
따라서 나는 “cloudfront 경로만 공개하고 이 경로 로만 호출해주세요” 같은 규칙이 아닌 api gateway에 IAM 정책(Policy)을 통해 아키텍처를 강제 (soure arn 설정을 연결해둔 cloudfront의 arn만을 허용하도록) 함으로써 의도치 않은 경로로의 접근 가능성을 제거하고 시스템의 안정성을 확보할 수 있었다.

2. POST 요청을 처리하기 위한 DB 도입기

유저 정보와 마이페이지에 대한 정보를 FE차원에서 해결하기 위해 POST요청이 필요한 타이밍까지 왔다.
백엔드 api를 바로 사용하면 좋겠지만 바로 사용할 수는 없는 상황이어서 간단하게 NoSQL을 사용하여 구현하였다.
우리는 k-contents 관련 장소들로 동선을 저장할 수 있는 기능이 있는데, 사용자 정의 동선 같은 경우는 직접 저장하고 마이페이지에서 불러올 수 있어야하는 기능이 필요했다. 따라서 새로운 함수를 생성해서 DB에 CRUD가 가능한 로직을 구축했다.
3. api 명세 작성 (swagger)
기존엔 팀 저장소의 docs/api 폴더에 contents.md ,locations.md 처럼 도메인 별로 api 형식을 정의해 두었다. 하지만 본격적으로 api를 운영하기로 정한이상, 프론트는 물론 백엔드에서도 필요한 데이터 형식을 같이 볼 수 있도록 OAS방식으로 명세를 작성하기로 하였다.
https://docs.tosspayments.com/resources/glossary/oas
내가 직접 작성하지는 않았고, api 경로와 응답 형식만 정리해서 AI가 작성하도록 시키고, 검토만 하는식으로 만들었다. 경로는 docs/api/openapi.yaml 에 정의해두었다. 확실히 이렇게 정리해서 응답 형식을 확인가능하니 개발 경험이 향상되는 느낌이었다. 특히 팀원에게 api에 대한 질문이 거의 없어질 정도의 효율을 느낀 것 같다.
