API Projection (성능 최적화, 설계 복잡성, 적용 기준)
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
API를 개발하다 보면 한 번쯤 이런 상황을 맞닥뜨립니다. 클라이언트는 딱 두세 개 필드만 쓰는데, 서버는 수십 개짜리 응답을 고스란히 내려보내고 있는 것입니다. 저도 실제 프로젝트에서 이 문제를 겪고 나서야 API Projection이라는 전략을 진지하게 들여다보게 됐습니다. 성능은 개선되지만 설계는 복잡해진다는 이 양날의 구조, 제가 직접 부딪히며 느낀 것들을 풀어보겠습니다.
성능 최적화, Projection이 실제로 얼마나 줄여주나
API Projection(프로젝션)이란 클라이언트가 응답에서 받고 싶은 필드를 직접 지정하고, 서버는 그 필드만 담아 응답을 내려주는 방식입니다. 쉽게 말해 "이것만 주세요"를 API 수준에서 가능하게 만드는 구조입니다.
전체 리소스를 그대로 내려주는 방식과 비교하면 차이가 꽤 큽니다. 응답 페이로드(Payload), 즉 실제로 전송되는 데이터 묶음이 줄어들면서 네트워크 전송 비용이 감소합니다. 직렬화(Serialization)란 객체를 JSON 같은 전송 가능한 형태로 변환하는 과정인데, 다뤄야 할 필드가 줄어드니 이 과정도 가벼워집니다. 서버 CPU 사용량이 실제로 줄어드는 효과가 여기서 나옵니다.
제가 직접 써봤는데, 모바일 환경에서 그 체감이 특히 뚜렷했습니다. 데이터 필드가 60개 이상인 리소스에 Projection을 적용했더니, 실제 클라이언트가 사용하는 필드는 8개 내외였고 응답 크기가 절반 이하로 줄었습니다. 저속 네트워크에서는 체감 로딩 속도가 눈에 띄게 달라졌습니다. 단순히 이론적인 수치가 아니라, 실사용자 입장에서 느껴지는 차이였습니다.
다만 이 효과는 Projection이 제대로 설계됐을 때만 나타납니다. 무분별하게 적용하면 오히려 역효과가 나는데, 그 이야기는 다음에서 이어집니다.
설계 복잡성, 생각보다 훨씬 깊은 곳까지 파고든다
Projection의 가장 큰 함정은 "클라이언트가 매번 다른 필드를 고를 수 있다"는 점입니다. 처음엔 유연해 보이는 이 특성이, 서버 입장에서는 꽤 무거운 숙제가 됩니다.
요청마다 필드 조합이 달라지면 서버는 그 조합을 검증하고, 응답 구조를 동적으로 조립하고, 누락된 필드는 어떻게 처리할지도 판단해야 합니다. 중첩 객체 구조에서는 이 복잡성이 기하급수적으로 늘어납니다. 솔직히 이건 예상 밖이었습니다. 단순히 응답에서 필드 몇 개를 빼는 작업인 줄 알았는데, 데이터 접근 계층 전체에 영향이 퍼졌습니다.
데이터베이스 쿼리도 문제입니다. 동적 쿼리(Dynamic Query), 즉 실행 시점에 조건에 따라 구조가 변하는 SQL이나 ORM 쿼리를 Projection과 함께 쓰면, 인덱스 활용이 제대로 안 되거나 전체 테이블 스캔이 발생할 수 있습니다. 잘못 설계하면 Projection 적용 전보다 오히려 쿼리 성능이 나빠지는 상황도 생깁니다. 제 경험상 이 부분을 사전에 검증하지 않으면 운영 단계에서 생각지 못한 병목을 만나게 됩니다.
GraphQL이 이 문제를 어느 정도 구조화된 방식으로 해결해준다는 점에서 관심을 받는 이유도 여기 있습니다. REST API에 Projection을 얹는 방식은 GraphQL처럼 스키마 레벨에서 강제되는 것이 아니라 개발자가 직접 관리해야 하기 때문에, 코드 복잡성이 훨씬 빠르게 올라갑니다. (출처: GraphQL 공식 문서)
유연한 데이터 제공과 일관성 저하, 두 마리 토끼의 딜레마
API Projection의 장점을 한 줄로 요약하면 "하나의 API로 다양한 요구를 소화한다"입니다. 클라이언트마다 별도의 API를 만들 필요가 줄어들고, 재사용성도 높아집니다. 실제로 여러 클라이언트(모바일, 웹, 어드민)가 동일한 엔드포인트를 공유하면서 각자 필요한 필드만 가져가는 구조는 꽤 깔끔하게 느껴집니다.
하지만 응답 일관성(Response Consistency) 문제가 뒤따릅니다. 응답 일관성이란 같은 API를 호출하더라도 항상 예측 가능한 구조의 응답이 돌아오는 성질입니다. Projection을 쓰면 클라이언트마다 받는 응답 구조가 달라지고, 이게 테스트와 디버깅을 꽤 까다롭게 만듭니다. "분명히 같은 API를 쓰는데 왜 응답이 다르지?" 하는 혼란이 팀 안에서도 생길 수 있습니다.
제가 실제로 이 상황을 겪었을 때, 클라이언트 개발자가 요청해야 하는 필드를 잘못 파악해서 빈 응답을 받고 오류라고 착각했던 사례가 있었습니다. 문서가 부족했던 탓이 크지만, 구조 자체가 가진 모호성도 한몫했습니다. 이 문제를 막으려면 허용 가능한 필드 목록을 명시적으로 제한하고, 기본 응답 구조를 별도로 정의해두는 것이 현실적인 해결책입니다.
API 명세 표준인 OpenAPI(구 Swagger)를 활용해 Projection 가능한 필드 범위를 문서화해두면 이 혼란을 크게 줄일 수 있습니다. (출처: OpenAPI Specification)
적용 기준, 모든 API에 넣으면 안 되는 이유
Projection이 무조건 좋다는 시각도 있는데, 저는 오히려 "어디에 쓰지 않을지"를 먼저 고민하는 편입니다. 필드 수가 적고 응답 구조가 단순한 API에 Projection을 얹으면 설계 복잡성만 늘어나고 실제 이득은 거의 없습니다.
Projection 도입을 고려할 때 제가 판단하는 기준은 크게 이렇습니다.
- 응답 필드가 20개 이상이거나 중첩 객체 구조가 깊은 경우 — 이 정도 규모부터 Projection의 실질적인 효과가 나타나기 시작합니다.
- 클라이언트가 다수이고 각각의 데이터 요구가 다를 때 — 모바일, 웹, 써드파티 등 요구 패턴이 명확히 갈릴 때 유리합니다.
- 네트워크 비용이 실제로 병목인 환경 — 트래픽 분석으로 확인된 경우에만 적용합니다. 추측으로 도입하면 오버엔지니어링이 됩니다.
- 데이터베이스 쿼리 성능을 사전에 검증할 수 있는 환경 — 동적 쿼리가 인덱스를 타는지 미리 확인하지 않으면 운영 리스크가 큽니다.
캐싱 전략과 함께 설계하는 것도 중요합니다. 캐시(Cache)란 자주 사용하는 데이터를 미리 저장해 빠르게 꺼내 쓰는 구조인데, Projection과 캐시를 같이 쓸 때는 필드 조합마다 캐시 키가 달라져야 하므로 캐시 히트율이 크게 떨어질 수 있습니다. 이 부분을 설계 단계에서 놓치면 캐시를 쓰는 의미가 없어집니다.
API Projection은 잘 쓰면 강력하지만, 아무 데나 넣으면 유지보수 부담만 키우는 양면적인 전략입니다. 저는 도입 전에 반드시 현재 API의 응답 크기와 클라이언트 사용 패턴을 먼저 측정해보기를 권합니다. 숫자로 확인된 병목이 있을 때 도입하면 그 효과가 명확하고, 팀 내에서 설득하기도 훨씬 쉽습니다. Projection을 처음 적용해볼 계획이라면, 가장 필드가 많고 사용 빈도가 높은 API 하나를 골라 파일럿으로 시작해보는 것이 현실적인 방법입니다.
관련 글
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기