How to Escape REST API Call Hell: The API Design Strategies Senior Engineers Actually Use
Translated from the original Korean post. 한국어 원문 보기 →
One screen, six API calls
I was poking at a dashboard a coworker built and opened devtools out of habit. One user profile screen. Six REST calls. Profile info, permissions, recent activity, notification settings, subscription status, stats — each one flying off on its own.
Every individual call came back under 200ms. The screen took 1.5 seconds to fill in. Some of the data depended on other responses, so the calls had to run in sequence. Each request passed. The sum of them didn't.
This is the classic trap of 2015-era REST design.

The illusion REST created
As REST caught on, a lot of teams started believing that "resource-oriented design" and "good API design" were the same thing. I believed it too, for a while.
New requirement, new endpoint. Edge case, another controller. Different client, another response shape. Repeat.
Nothing looked wrong in code review. But every time I actually used the product, something felt heavy.
It comes down to one thing: we confused system design with endpoint growth. Adding endpoints isn't design, it's just increasing surface area. And while that happens, the client ends up knowing far too much about the backend's internals. Which data, in which order, to assemble a complete screen — that responsibility quietly slides over to the frontend.
The real problem is the seams
The most maddening version of this looks like: every service's monitoring is green, every individual API response time passes, and users say "the app is slow." All the parts are fine and the whole experience is bad. I've seen this pattern plenty of times in operations. No red lights anywhere on the dashboard, and yet.
The culprit is usually not the services. It's the seams between them. One service runs slightly slower than its neighbor, or the network wobbles a bit, and the whole screen's load time slips badly. With sequential calls, the slowest hop sets the pace. Meanwhile the frontend isn't drawing a screen — it's busy negotiating with backend services over when and in what order it gets its data.
What senior engineers do differently
People who've watched this pattern long enough change the question itself.
"How should I expose the next resource?" ❌
"What is the user actually trying to do?" ✅
Looks trivial. It flips the entire direction of the conversation. Your head stops drawing resource lists and starts following the shape of user behavior. Flow, not destination.
Experience-oriented API design
Look at it that way and this structure falls out naturally.
클라이언트
↓
사용자 액션 하나 → 요청 하나
↓
경험 API (BFF/GraphQL/통합 API)
↓
프로필 서비스, 권한 서비스, 활동 서비스...
↓
화면에 맞춰 구성된 하나의 응답
The value here goes beyond cutting the number of round trips. Orchestration moves somewhere you can actually control it, so retries, fallbacks, caching, and partial-failure handling all move inside the server. Observability changes too — instead of scattered calls, one user journey shows up as one path. The client gets to focus on UI instead of data assembly.
The second part is what really landed for me on the operations side. Six scattered calls means logs scattered across six places. And the one line you need is always in the wrong one. Tie the flow together and there are fewer places to chase.
Tools are just tools
Lay out the options people actually reach for and it's roughly this.
| 상황 | 선택하는 기술 | 이유 |
|---|---|---|
| 고정된 화면, 예측 가능한 데이터 | BFF (Backend for Frontend) | 성능 최적화와 캐싱에 유리 |
| 화면이 자주 바뀌고 유연한 쿼리 필요 | GraphQL | 클라이언트가 필요한 데이터만 요청 가능 |
| 서비스 간 통신, 엄격한 계약 | gRPC | 타입 안정성과 성능 |
| 실시간 업데이트 | WebSocket/Server-Sent Events | 폴링은 2026년에 어울리지 않음 |
The table makes it clear there's no single right answer. Loyalty to a particular technology isn't the criterion. The goal is to keep users from absorbing your backend's fragmentation directly. Hit that, and you pick the tool that fits the situation.

Mistakes I've made
I've fallen into this trap plenty of times myself.
"Isn't adding one more endpoint the fastest, simplest thing here?" I thought that a lot. In the moment it felt like the most efficient choice. Looking back, I was pushing complexity onto the client.
And the bill always came back in the same order. Users pay first, through slow loading. Complaints pile up and the product team pays. A few months later engineering pays, in refactoring. The fast choice was the expensive one. The time I spent later untangling scattered calls dwarfed the time it took to add the endpoint.
A realistic take for 2026
The good backend teams I've seen lately don't treat REST, GraphQL, or gRPC as religion. They're tools, not identity. Those teams don't define themselves by which technology they use.
What they actually weigh is simple: minimize coordination cost, cut round trips, and put business logic where errors are easy to manage.
One thing gets clearer with experience. Good API design isn't exposing everything cleanly — it's hiding the right amount of complexity inside so the product feels simple. Deciding what to expose and what to conceal is most of the design work.

Wrapping up
Users don't care how many services you run or how your database tables are split. They care whether the screen is fast and reliable.
If a team's core feature still rests on "a sequence of REST calls the client has to order carefully," the question to ask isn't when it was built.
The real problem is that the system is packaging its internal mess as architecture and pushing it outward. That bill lands on users first, and then on us.
Was this post helpful?
One click helps me write the next one