Frontend development without a backend
Updated
Waiting on the backend team — or on access to a locked-down upstream system — shouldn't block frontend work. If you agree on an OpenAPI contract first, you can build against a mock generated from it and switch to the real API later with a single config change.
1. Agree on the contract
Write (or generate) the OpenAPI spec together with the backend team. Be specific about types, formats and enums — the mock is only as realistic as the spec. Commit it to the repo, for example as openapi.yaml.
2. Run the mock server locally
git clone https://github.com/venkatbandaru99/mirage.git
cd mirage && yarn install
node src/index.js --spec ../my-app/openapi.yaml --port 4010
Every endpoint in the spec is now live on http://localhost:4010. CORS is enabled for all origins, so your dev server on another port can call it directly.
3. Point your app at the mock
Keep the API base URL in an environment variable so switching is a config change, not a code change. With Vite:
# .env.development
VITE_API_URL=http://localhost:4010
# .env.production
VITE_API_URL=https://api.example.com
// api.ts
const API_URL = import.meta.env.VITE_API_URL;
export async function getCustomers() {
const res = await fetch(`${API_URL}/customers`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
Alternatively, proxy API paths through the Vite dev server so the frontend uses relative URLs:
// vite.config.ts
export default defineConfig({
server: {
proxy: {
'/customers': 'http://localhost:4010',
'/orders': 'http://localhost:4010'
}
}
});
4. Build against varied data
Because the mock generates new data on every request, your UI is exercised with different string lengths, array sizes and enum values, and optional fields are sometimes missing. That surfaces layout and null-handling bugs long before production.
5. Switch to the real API
When the backend is ready, change VITE_API_URL (or the proxy target). Because both sides built against the same contract, integration is usually uneventful.
VITE_API_URL at the shared URL (for example https://mirageapi.com/m/Ab3dE7xY). It's public and CORS-enabled.Test loading and error states
Point the app at …/customers?__delay=2000 to see your loading spinners, or ?__status=500 to check your error UI — no backend changes needed.