Workshops ... Part 5: Connect frontend and backend

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.

Questions & Answers

Sign up to ask questions, track your progress, and get access to other workshops · Already have an account? Sign in