Blog #42: When the Backend Changes the Schema and the Fragility of the Frontend
The story of a project collapsing just because the Backend renamed a field and a lesson on the Data Mapping layer.
To my past self,
Do you still remember the shock when the Dashboard suddenly failed to display the revenue chart? The Backend simply changed a field name from total_price to totalPrice for "naming standards," but they forgot to tell you. And just like that, all your calculation logic on the Frontend was paralyzed.
At that time, you frantically searched for the keyword total_price throughout the entire project to fix it by hand. You felt like a slave to the API.
The Problem: Over-dependence
Simply put, you were letting the Frontend "speak" directly in the Backend's language. When the Backend changed its voice, the Frontend immediately went deaf. You were using exactly what the API returned to display on the interface, without any filter in between.
Current Perspective: The Vital Buffer Layer
Now, I never directly use API results in display components. A common junior mistake is mapping API variables directly into a component's State.
// How you used to do it (dangerous)
const [orders, setOrders] = useState([]);
useEffect(() => {
fetch('/api/orders').then(res => setOrders(res.data));
}, []);
// In JSX
return orders.map(order => <span>{order.total_price}</span>);
The problem is that the keyword total_price now appears in 20 different places in the project. When the Backend changes the name, you have to fix it in 20 places. That is a loose and fragile design.
Sustainable Solution: DTO and Data Mapping
In sustainable systems, we need a layer called a Mapper or Adapter. As soon as data arrives at the Frontend, we convert it into the format the Frontend desires (DTO - Data Transfer Object).
Comparison:
- Quick fix: Fix code wherever there's an error. Fast but leaves a high risk of missing bugs.
- Sustainable way: Create a data mapping function right at the service layer. If the Backend renames a field, I only need to fix a single line in this mapping function. The entire UI below keeps its logic because they use the variable names I've defined.
// Sustainable way: Separating data logic
const orderMapper = (apiData) => ({
id: apiData.id,
totalPrice: apiData.total_price || apiData.totalPrice || 0, // Handles both old and new
customerName: apiData.customer_info?.name
});
const orders = rawData.map(orderMapper);
Practical Lesson
The Frontend should have sovereignty over its own data structure. Don't let a change in another system (Backend) break your logical thinking. Taking an extra 5 minutes to write a mapping function will save you from hours of Find & Replace later.
Build a shield to protect your code.
Notes on the necessary independence of data.
Series • Part 42 of 50