Part 5: Connect frontend and backend
So far the frontend and the backend have never spoken to each other. The
frontend in frontend/ still runs on its mock backend, and the FastAPI backend
in backend/ runs on its own at http://localhost:8000. In this part we point
the frontend at the real backend and run both together with one command.
Switch the frontend to the real backend
Back in Part 1: Frontend with Lovable, Lovable gave us two
clients behind the services layer: mockApi.ts and api.ts. Everything so far
has used the mock, and now we flip to the real one.
Ask the assistant to do the swap so the wiring stays consistent:
Switch the frontend to use the real backend client (services/api.ts) instead of
the mock everywhere it's imported. The backend implements the openapi.yaml at
the repo root and runs at http://localhost:8000. Keep the mock in the repo as a
fallback.
The real client reads the backend URL from config.ts, which falls back to
http://localhost:8000 but prefers an environment variable.
Set it explicitly for local development in frontend/.env.development:
VITE_API_BASE_URL=http://localhost:8000
The backend already allows cross-origin requests - main.py enables CORS for
all origins - so the browser at localhost:5173 can call the API at
localhost:8000 without being blocked. That permissive setting is fine for
local work and is one of the things to tighten before going public, which
Where to go from here calls out.
Run both servers
The backend and frontend each run on their own.
Start the backend in one terminal:
cd backend && uv run uvicorn app.main:app --reload --port 8000
Start the frontend in a second terminal:
cd frontend && npm run dev
Now the React app at http://localhost:5173 is talking to FastAPI at
http://localhost:8000. Sign up for a real account, submit a score, and reload
the leaderboard - the data comes from the backend, not the mock.
Expect to debug here
This is the step where the two sides disagree, and that's normal.
Common mismatches include:
- a field named one way in the frontend and another in the backend
- a 422 from a request body that doesn't match
- a missing trailing slash on a route
Read the error in the browser console or the uvicorn log, hand it to the assistant, and ask for the fix:
Signing up returns a 422 from the backend. Here's the request the frontend
sends and the error the backend logs: <paste both>. Make them agree, and follow
the openapi.yaml.
Let openapi.yaml settle the disagreement, and change whatever diverges from
it. Once every page works against the real backend, the data still lives only in
memory and disappears on restart. Before we fix that with a real database, we
wrap these commands in a Makefile in Part 6: A Makefile for the project.