I Built ONE Backend Route That Replaced 5 Features
A few months ago, my backend looked busy.
Not complex.
Not advanced.
Just busy.
I had separate routes for everything:
/chat/search/summarize/recommend/extract
Each route worked.
Each route shipped.
Each route slowly became a maintenance problem.
So I did something that felt risky at first:
👉 I deleted four routes and kept just one.
This post explains what changed, why it worked, and what this teaches new developers about real backend design.
The Problem I Didn’t See at First
At a glance, multiple routes felt “clean”:
- One route = one feature
- Clear separation
- Easy to explain
But in practice, the problems showed up fast:
- Repeated validation logic
- Repeated authentication checks
- Repeated error handling
- Slightly different prompt logic everywhere
- Frontend tightly coupled to backend behavior
Every new feature meant:
- New route
- New controller
- New bugs
I wasn’t scaling intelligence.
I was scaling surface area.
The Insight That Changed Everything
One day it clicked:
These aren’t five different systems.
They’re five behaviors of the same system.
Let’s look at them again:
- Chatbot
- Semantic search
- Text summary
- Recommendations
- Data extraction
Every single one does the same thing at a high level:
Input → Context → Reasoning → Output
Only the intent changes.
So instead of designing feature-based APIs, I redesigned around capabilities.
The New Architecture (One Route, Many Behaviors)
Here’s the mental model I switched to:
Frontend
↓
POST /ai
↓
Intent + Context
↓
Decision Layer
↓
LLM / Tools / Retrieval
↓
Response
The frontend no longer tells the backend how to behave.
It only tells it what it wants.
That distinction changed everything.
The ONE Backend Route
Conceptually, the API became very simple:
POST /ai
{
"intent": "summarize",
"input": "long article text here",
"context": "optional extra data"
}
That’s it.
No /summarize route.
No /search route.
No /recommend route.
Just intent-driven behavior.
How One Route Replaced Five Features
Here’s how the same endpoint handles different features.
Chatbot
Intent: chat
Instruction: Answer like a helpful assistant
Semantic Search
Intent: search
Context: Top matching documents
Text Summary
Intent: summarize
Instruction: Return exactly 3 bullet points
Recommendations
Intent: recommend
Context: User history and preferences
Automation / Extraction
Intent: extract
Output format: JSON only
The route never changed.
The intent did.
That was the breakthrough.
Why This Pattern Is Powerful for New Developers
Most beginners struggle because they think in terms of features.
Real systems scale by thinking in terms of decisions.
This pattern teaches core engineering principles:
Abstraction
One system, many behaviors.
Separation of Concerns
- Frontend → declares intent
- Backend → owns logic and intelligence
Extensibility
New feature = new intent, not new API.
Maintainability
One place to:
- validate
- log
- secure
- observe
- improve
What This Taught Me About AI Systems
This wasn’t really about AI.
It was about architecture.
Some hard-earned lessons:
- AI apps are 80% backend design, 20% model choice
- Prompts are configuration, not magic
- Centralized intelligence beats scattered logic
- Fewer APIs mean fewer bugs
- Clean architecture beats clever code
The LLM didn’t make my system better.
The design did.
When This Pattern Does NOT Work
This is important.
Don’t use this approach if:
- Features require very different security boundaries
- Latency requirements vary wildly
- Strict compliance separation is required
- You need hard isolation between tenants
Architecture is always about trade-offs, not rules.
The Final Mental Model
Great systems don’t grow by adding routes.
They grow by adding better decisions.
If you’re a new developer, learning this way of thinking will help you far more than memorizing another framework.
Final Thought
Deleting four routes felt uncomfortable.
But it forced me to design one system that actually understood intent.
And that single decision made my backend:
- cleaner
- cheaper
- easier to extend
- easier to reason about
If this post helped you think differently about backend design, consider sharing it — it might help another developer avoid the same mistakes.
Thanks for reading 🙌
Top comments (2)
Makes sense. Like a getAIResponse() function that you pass your particulars to
Exactly 👍
That’s the right intuition — a single getAIResponse()-style interface, but with the backend owning the decision logic (intent, context, validation), not just passing a prompt through.