Chapter 8

Add React, Vite, and FastAPI

Replace the static page with a small React frontend and typed FastAPI backend, each built as its own image.

Just started Saved in this browser.

The full-stack snapshot keeps one responsibility per container. The frontend is the user interface: Vite builds React into static files, and nginx serves them. The backend is an API (application programming interface): FastAPI answers JSON requests. The browser joins them through HTTP. This chapter runs both containers locally; Chapter 9 moves the same images into Kubernetes.

Browser traffic split through ingress to React and FastAPI

Last updated: 2026-07-20

Audience

Who this chapter is for

This chapter is for beginners who finished the static-container lessons and are ready for two cooperating services. You need Docker only—no host Node.js or Python install.

Step by step

Download this chapter's files

Use your browser to download either ivia-chapter-08.tar.gz or ivia-chapter-08.zip. The archive is self-contained; you do not need this tutorial repository.

Open a terminal after the browser download:

cd ~/Downloads
tar -xzf ivia-chapter-08.tar.gz
cd ivia-chapter-08

All remaining relative paths in this chapter start from that extracted directory.

Do this

The challenge

Challenge: build and run both full-stack containers locally, then load a React page that displays a greeting returned by FastAPI.

Prepare

Prerequisites

  • Docker or a compatible container CLI.
  • Ports 5173 and 8080 available.
  • The extracted Chapter 8 package, with your terminal in its top-level directory.
  • No host Node.js or Python installation; the images contain build tools.
Outcome

Learning goals

After this chapter, you will be able to:

  • Identify frontend and backend responsibilities
  • Understand Vite build output and nginx runtime serving
  • Read minimal FastAPI routes
  • Connect two containers through browser-visible ports
  • Validate each service independently before blaming CORS
Step by step

Inspect the architecture

find fullstack-app -maxdepth 3 -type f -print
sed -n '1,200p' fullstack-app/frontend/src/App.jsx
sed -n '1,200p' fullstack-app/backend/app/main.py

config.js loads before React, so deployment can replace the API URL without rebuilding. The local default is http://localhost:8080. FastAPI permits http://localhost:5173 through CORS (browser policy that controls which web pages may call which APIs).

Step by step

Build both images

We build two images so each service can scale and release independently later.

docker build -t simple-backend:local fullstack-app/backend
docker build -t simple-frontend:local fullstack-app/frontend

Dependency manifests are copied before source files so the builder can reuse dependency layers when only source changes. You should see successful tags for both images.

Step by step

Run and connect

Start the backend first so the frontend has something to call:

docker run --rm --name simple-backend -d \
  -p 8080:8080 \
  -e GREETING='Hello from two containers!' \
  simple-backend:local
docker run --rm --name simple-frontend -d \
  -p 5173:8080 simple-frontend:local

Validate FastAPI directly (this check ignores the browser):

curl --fail http://localhost:8080/health
curl --fail http://localhost:8080/api/greeting

You should see JSON with "status":"ok" and a greeting containing Hello from two containers!.

Open http://localhost:5173. It should show the same greeting. Inspect and stop:

docker logs simple-backend
docker logs simple-frontend
docker stop simple-frontend simple-backend

React runs in the browser, not inside the frontend container’s Node process at runtime. Therefore local localhost:8080 reaches the host-published backend. Chapter 9 replaces that URL with an ingress hostname inside Kubernetes.

Verify

Expected validation

Health returns {"status":"ok"}. Greeting returns JSON containing Hello from two containers!. The browser displays that greeting without a CORS error in its developer console.

Troubleshoot

Troubleshooting and common pitfalls

  • Failed to fetch: check docker ps and curl the API directly.
  • CORS error: open exactly http://localhost:5173; scheme, hostname, and port define an origin.
  • Dependency download fails: check network and registry access; host dependencies do not fix a container build.
  • Backend exits: inspect logs; import errors often indicate a changed build context.
  • Old page: rebuild and recreate the frontend container, then hard-refresh.
  • Vite expected at runtime: this image uses Vite only to build; nginx serves production files.
Practice

Recap and practice

Recap: Two images, two ports, one HTTP contract. Validate the API with curl before debugging the browser.

Try to explain in your own words:

  1. Why can React talk to localhost:8080 even though it was served from port 5173?
  2. What is the difference between this local Docker setup and the Kubernetes deploy in Chapter 9?

Exercise: Change GREETING on a new backend container run and confirm both curl and the browser show the new text.

Stretch: Read fullstack-app/frontend/public/config.js (or equivalent) and write one sentence about why runtime config beats rebuilding the frontend for every API URL.

Reference

Official references

Just started Saved in this browser.