Part 7: Connect frontend and backend

So far the frontend and the backend aren't connected. 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 connect them, using the make commands we set up in Part 6: A Makefile for the project.

Switch the frontend to the real backend

Back in Part 1: Frontend with Lovable, Lovable gave us two service implementations behind services/index.ts: mock.ts and http.ts. Everything so far has used the mock, and now we switch the entrypoint to the real HTTP client.

Ask the assistant to do the swap in the service layer:

Switch the frontend to use the real backend client

The HTTP client calls the backend under a relative /api path. So the browser sends every request to a single origin in local development, the Vite dev server proxies /api to the backend on http://localhost:8000.

The Lovable template already configures this in frontend/vite.config.ts:

server: {
  proxy: {
    "/api": {
      target: "http://localhost:8000",
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, ""),
    },
  },
}

With the proxy in place, the frontend at localhost:8080 calls /api/... on its own origin. The dev server forwards it to FastAPI, so there's no cross-origin request. If you instead point the client straight at http://localhost:8000, the browser blocks it with a CORS error.

This is the most common first error when you connect a separate frontend and backend. You either keep this proxy or enable CORS on the backend. Tighten the CORS settings before going public, as Where to go from here explains.

Run both servers

The backend and frontend each run on their own, so start them with the two targets from the Makefile, one in each terminal.

Start the backend in one terminal:

make backend

Start the frontend in a second terminal:

make frontend

Now the React app at http://localhost:8080 calls 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.

Run both with one command

Two terminals and two commands work, but now that the frontend needs the backend running, it's easier to start both together.

Ask the assistant to add a dev target that does it:

Add a dev target to the Makefile that runs the backend and the frontend together
in one command, and stops both on Ctrl-C.

The assistant's first version puts all the startup logic into the Makefile target, which quickly becomes hard to read.

Ask it to move that logic into a script:

Move the dev startup logic into scripts/dev.sh and have the Makefile target
just call the script.

Now the target is one line:

dev:
    @./scripts/dev.sh

And scripts/dev.sh starts both servers, remembers their process IDs, and shuts both down on Ctrl-C:

#!/usr/bin/env bash
set -euo pipefail

backend_pid=""
frontend_pid=""

cleanup() {
    trap - INT TERM EXIT
    [[ -n "$backend_pid" ]] && kill "$backend_pid" 2>/dev/null || true
    [[ -n "$frontend_pid" ]] && kill "$frontend_pid" 2>/dev/null || true
}
trap cleanup INT TERM EXIT

(cd backend && uv run python main.py) &
backend_pid=$!

(cd frontend && npm run dev) &
frontend_pid=$!

wait -n "$backend_pid" "$frontend_pid"

From now on one command starts the whole app:

make dev

Expect to debug here

In this step the two sides often 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, give it to the assistant, and ask for the fix.

Use openapi.yaml to decide which side is right, and change whatever differs from it.

Commit the integration:

git add .
git commit -m "Connect frontend to the backend API"

Every page now works against the real backend, but the data still lives only in memory and disappears on restart. We fix that with a real database in Part 8: Real persistence with SQLite.

Questions & Answers

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