跪拜 Guibai
← Back to the summary

Mock Data and a One-Line baseURL Switch Let Frontend Development Run Without a Backend

Opening: Today I learned a "collaboration mindset" for full-stack projects — frontend interface engineering under frontend-backend separation. I used to think: the frontend has to wait for the backend to finish writing the interfaces before development can start. Then the teacher said: "Stupidly waiting for the backend to provide interfaces? The frontend absolutely doesn't need to wait!" The frontend defines its own interfaces, mocks its own data, and gets itself running first. When the real backend interfaces are done, just switch the baseURL in one go. After hearing this, it clicked — frontend-backend separation isn't just about "separating code," it's about "decoupling development rhythms."


1. The "Three Carriages" of Frontend-Backend Separation

1.1 Independent Frontend Development

The teacher said:

"The three carriages of independent frontend project development: Components (reactive) + Routing + State Management (the bank)."

Frontend Three Carriages
├── Components: React (reactive UI)
├── Routing: react-router (page switching)
└── State Management: zustand (data "bank")

These three things combined make the frontend itself a complete application — it can be developed independently without a backend.

1.2 The "Single Coupling Point" Between Frontend and Backend

The teacher said:

"/api interface requests — can frontend and backend be separated? The only coupling. The frontend needs to wait for the backend to provide interfaces to render data state."

Frontend and backend code can be completely separated, but the "data interface" is their only connection point:

Frontend (React) ─── /api/todos interface ─── Backend (Node/Koa)

This single coupling point is exactly what "frontend interface engineering" aims to solve.


2. Why Does the Frontend Need an api Directory?

2.1 Pain Point: Backend Interfaces Are Often Not Ready in Time

The teacher said:

"Backend interfaces often cannot be provided in a timely manner. The frontend interface layer — manages all interfaces, axios configuration, fakes data first, baseURL one-click switch. A part of frontend engineering, namely API engineering."

If the frontend stupidly waits for backend interfaces:

Frontend: Waiting for the backend to write the /api/todos interface…
Backend: Still working on other requirements…
Frontend: Can't write the page, just waiting!

With a "frontend interface layer":

Frontend: Define /api/todos yourself first, use mock data!
Backend: Take your time writing the real interface, no rush!
Frontend: Page development proceeds normally, no waiting at all!

2.2 Responsibilities of the api Directory

Look at todos.js:

// One module per JS file
import axios from './config';

// The api directory's responsibility: not to go directly to the backend, sometimes the backend hasn't been developed yet, separated from us
export const getTodos = async () => {
    const res = await axios.get('/todos');
    return res.data;
};

The api directory is the "unified management entry point for frontend interfaces":

Feature Explanation
One module per file todos.js manages todos interfaces, user.js manages user interfaces
Unified export All interface functions are centrally managed, easy to find and modify
Doesn't hit the backend directly Goes through mock first, switches when the backend is ready

3. Axios Configuration: One-Click baseURL Switching

3.1 Why Use Axios?

Look at config.js:

import axios from 'axios';

// Instantiate axios
// The downside of fetch is limited functionality
// app /api/todos -> http://localhost:3000/todos
// Unified management, upgrade from fetch to axios
const instance = axios.create({
    baseURL: '/api',               // dev: frontend simulated request address /api/todos
    // baseURL: 'http://localhost:3000',  // prod: real backend address (commented out as backup)
    timeout: 5000,
});

export default instance;

The teacher said:

"The downside of Fetch is limited functionality. The App application upgrades to axios — unified management."

Where is axios better than fetch?

Comparison fetch axios
Timeout setting Must manually wrap AbortController timeout: 5000 done in one line
Interceptors None Yes (request/response interceptors)
baseURL Must manually concatenate Configure once, globally effective
Error handling Manual judgment Unified error handling

3.2 The Secret of One-Click baseURL Switching

The two baseURL lines in config.js:

baseURL: '/api',                          // Development phase: use mock
// baseURL: 'http://localhost:3000',       // Integration phase: use backend

Switching only requires commenting/uncommenting one line!

Development phase:
Frontend requests /api/todos
  ↓ (mock interception)
Returns mock data

Integration phase:
Comment out '/api', enable 'http://localhost:3000'
Frontend requests http://localhost:3000/todos
  ↓
Returns real backend data

This is "one-click switching" — the rhythm of frontend-backend separation is decoupled this way.


4. Mock Data: Let the Frontend Run First

4.1 Why Mock?

The teacher said:

"The frontend needs data state, provided by data interfaces. Cannot directly hit backend data interfaces (frontend-backend separation, don't hit inconsistency). The frontend also needs an independent and complete application development engineering system, incorporating frontend interface engineering."

Frontend development cannot depend on the backend's progress — mock is the frontend's own "fake backend."

4.2 MockJS + Vite Configuration

The teacher said:

"MockJS + Vite configuration — mock directory: export default [{ url: '/api/todos', method: 'get', response: [...] }]."

// mock/todos.js (illustrative)
export default [
    {
        url: '/api/todos',
        method: 'get',
        response: [
            { id: 1, text: 'Learn React', completed: false },
            { id: 2, text: 'Learn Routing', completed: false },
        ]
    },
];

The role of the mock directory: when the frontend requests /api/todos, Vite's mock plugin intercepts the request and returns this fake data.


5. Complete Page + Interface Flow

5.1 Todos Page

Look at Todes.jsx:

import { getTodos } from '../api/todos';
import { useEffect, useState } from 'react';

function Todos() {
    const [todos, setTodos] = useState([]);

    useEffect(() => {
        // IIFE Immediately Invoked Function Expression
        (async () => {
            const data = await getTodos();
            setTodos(data);
        })();
    }, []);

    return <h1>Todos</h1>;
}

Standard flow for a page fetching data:

Component mounts
  ↓ useEffect ([] runs only once)
getTodos()               ← Calls the interface function from the api directory
  ↓ axios request
/api/todos               ← baseURL('/api') + path('/todos')
  ↓ mock interception (development phase)
Returns fake data
  ↓ setTodos(data)
Reactive page update

5.2 Route Configuration

Look at App.jsx:

import React, { lazy, Suspense } from 'react';
import { Routes, Route, BrowserRouter as Router } from 'react-router-dom';
import Nav from './components/Nav';

const Home = lazy(() => import('./pages/Home'));
const Todos = lazy(() => import('./pages/Todes'));

function App() {
    return (
        <Router>
            <Nav />
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/todos" element={<Todos />} />
            </Routes>
        </Router>
    );
}

All the routing knowledge learned previously is used here: BrowserRouter, Routes/Route, lazy loading, Link navigation (inside Nav).


6. Complete Architecture Diagram

Frontend (Independent Application)
├── Page Routing: pages/ (Home, Todos) ── react-router
├── Components: components/ (Nav) ── React componentization
├── Interface Layer: api/ (todos.js) ── axios unified management
│     └── config.js: axios instance + baseURL
├── Mock Data: mock/ (fake interfaces during development)
└── State Management: zustand (data "bank")
          ↓ /api interface (single coupling point)
Backend (Node/Koa)
└── Real Interface: /todos returns JSON

The key to frontend-backend collaboration: the frontend interfaces with the backend through the /api interface layer, using mock during development and switching baseURL during integration.


7. Summary: Frontend Interface Engineering

Concept Explanation
Frontend-Backend Separation Frontend three carriages (Components + Routing + State Management) developed independently
Single Coupling Point /api interface
api Directory Unified management of frontend interfaces, one module per file
axios Upgraded request library, baseURL/timeout/interceptors
baseURL Switching Use /api (mock) during development, switch to real address for integration
Mock Data Frontend creates its own fake data, doesn't wait for the backend
Development Rhythm Decoupling Frontend and backend each work on their own, integrate when interfaces are ready

The core idea of frontend interface engineering: the frontend shouldn't stupidly wait for backend interfaces — define your own interface layer, mock your own data, run the entire application yourself, and when the backend interfaces are ready, switch the baseURL in one click. This is the true value of frontend-backend separation: decoupled development rhythms, doubled efficiency.


Final Thoughts

Today's biggest takeaway was understanding the idea of "frontend interface engineering." I used to think "frontend waits for backend" was a matter of course, but now I know — the frontend can absolutely run first, mock data is the frontend's "fake backend." When the real backend is ready, change one line of baseURL to switch over.

And today, everything learned previously was tied together: routing (lazy + Routes), axios configuration, useEffect async requests, modular directory structure (api/pages/components)… a complete set of full-stack project mindsets, all in place.

Next time an interviewer asks you: "In frontend-backend separation, how does the frontend not wait for backend interfaces?"

You can calmly say:

"In frontend-backend separation, the frontend achieves not waiting for the backend by establishing 'interface engineering.' The specific approach: ① In the api/ directory, uniformly manage all interface functions (like getTodos()), one module per file; ② Configure an axios instance with baseURL: '/api' pointing to the development environment's mock service; ③ Use MockJS to define fake interface data in the mock directory; when the frontend requests /api/todos, Vite intercepts and returns mock data, allowing normal page development; ④ Once the real backend interface is complete, switch the baseURL in one click to the real address (like http://localhost:3000) to complete integration. This way, frontend and backend development rhythms are completely decoupled, with no mutual blocking."

Then look at the interviewer's satisfied expression and silently think: This move, solid again.


All code examples in this article are from classroom learning materials, real and runnable.

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

Darling噜啦啦

[Strong][Strong]