Full-Stack Integration — Teams Practical
Connect React Frontend with Express Backend (Teams Session)
This file is a practical session for Teams that merges the lecture and practice content to build a first version of the full-stack integration of the review aggregator app.
One-liner
This file is a ready-to-run 2-hour practical session for Teams that merges the lecture (webdev_06_L_FullStackIntegration.qmd
) and practice (webdev_06_P_FullStackIntegration.qmd
) content while omitting Docker and optional extensions.
Overview (Goal, Duration, Audience)
- Duration: 120 minutes (2 hours)
- Audience: Students who have completed the React frontend, Express backend, and MySQL exercises
- Goal: Replace mock API calls with real HTTP requests, fix CORS, wire end-to-end flow (scraper → backend → DB → frontend), and verify in the browser
Instructor contract (inputs / outputs / success criteria)
- Inputs: Running frontend dev server (http://localhost:5173), running backend (http://localhost:4000), MySQL with
reviews
table & test product id (e.g., product 1) - Outputs: Frontend makes real HTTP calls, “Fetch Reviews” triggers backend scrape, reviews and aggregated stats appear in the UI and persist in MySQL
- Success criteria (must be verifiable):
- No CORS errors in browser console
- “Fetch Reviews” triggers backend endpoint and returns new reviews
- UI updates reviews list and stats
- Database contains persisted reviews
Edge cases to plan for
- Services not running (backend, DB, frontend)
- Wrong endpoints or ports (different ports than defaults)
- Network / fetch failures (timeout, DNS)
- 404 for missing product id
- Scraper returns no new reviews
Required pre-session checklist (ask students to complete beforehand)
- Clone repository and checkout their working branch
- Have the backend running:
cd backend && npm run dev
(should listen on port 4000) - Have the frontend running:
cd frontend && npm run dev
(should be on port 5173) - Have MySQL available and accessible by the backend, with sample data for product id 1
- Open the browser and the React app at http://localhost:5173
Teams logistics & facilitation tips
- Use gallery view for instructor demo, then switch to presenter mode for code walkthrough.
- Create breakout rooms (3–4 students per room) during the 75m hands-on block. Assign one TA/instructor per 2 rooms if possible.
- Provide a single pinned message with the checklist and the backend/frontend run commands.
- Ask students to share their screen if they get stuck; use “Request control” sparingly.
- Use a short poll at 00:25 to check readiness: “Is backend running? (Yes / No)” and route stragglers to a help breakout.
- Encourage students to post console errors in the chat; TAs triage them.
Instructor script & live demo notes
- Show CORS problem quickly: open browser console and attempt a fetch from frontend to backend without CORS configured.
- Explain CORS origin concept and why Express must explicitly allow the frontend origin.
- Show the minimal CORS fix in
backend/src/app.js
(orserver.js
):
// backend/src/app.js
const cors = require('cors');
.use(cors({
apporigin: 'http://localhost:5173',
credentials: true
;
}))
// Make sure this is placed BEFORE your route handlers
- Explain environment variables in the frontend (Vite):
VITE_BACKEND_URL=http://localhost:4000
and how to useimport.meta.env.VITE_BACKEND_URL
. - Show the state-sync pattern (trigger scraper POST → GET reviews → GET aggregate) and how to update React state.
Hands-on exercises (detailed)
Each exercise has a short goal, exact files to edit, and verification steps.
Exercise A — Fix CORS (15m) - Goal: Allow the frontend origin to call backend endpoints - Files: backend/src/app.js
or backend/src/server.js
- Instructor: share the snippet above, walk students through editing and restarting backend - Verification: - From frontend console run:
fetch('http://localhost:4000/api/products/1/reviews')
.then(r => r.json())
.then(console.log)
.catch(console.error);
- Expect: Either JSON or a network-level response, but no CORS error in console
Exercise B — Create real API module (25m) - Goal: Replace mock API and commit a frontend/src/api/reviewsAPI.js
that talks to backend - File to create/update: frontend/src/api/reviewsAPI.js
- Instructor-provided reference code (students copy/adapt):
// frontend/src/api/reviewsAPI.js
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:4000';
const handleResponse = async (response) => {
if (!response.ok) {
// map common errors if desired
switch (response.status) {
case 400:
throw new Error('Invalid request (400)');
case 404:
throw new Error('Not found (404)');
case 503:
throw new Error('Service unavailable (503)');
default:
throw new Error(`HTTP ${response.status}`);
}
}return response.json();
;
}
export const fetchReviews = async (productId) => {
const response = await fetch(`${BACKEND_URL}/api/products/${productId}/reviews`);
return handleResponse(response);
;
}
export const triggerReviewFetch = async (productId) => {
const response = await fetch(`${BACKEND_URL}/api/products/${productId}/fetch`, {
method: 'POST'
;
})return handleResponse(response);
;
}
export const getReviewStats = async (productId) => {
const response = await fetch(`${BACKEND_URL}/api/products/${productId}/aggregate`);
return handleResponse(response);
; }
- Verification:
- In browser console, import or call these functions from the running app. You should get sensible JSON or handled errors (no CORS error).
Exercise C — Wire fetch flow in React component (20m) - Goal: Update the review component to use the new API module and implement the fetch flow - Files: e.g., frontend/src/pages/ReviewAggregatorPage.jsx
or similar review component - Replace import from mock module to:
import { fetchReviews, triggerReviewFetch, getReviewStats } from '../api/reviewsAPI';
- Example handler (in component):
const handleFetchReviews = async () => {
try {
setLoading(true);
setError(null);
// 1. Trigger scraper
const fetchResult = await triggerReviewFetch(productId);
// 2. Get updated data
const reviewsData = await fetchReviews(productId);
const statsData = await getReviewStats(productId);
// 3. Update state
setReviews(reviewsData);
setStats(statsData);
catch (err) {
} setError(err.message || 'Unknown error');
finally {
} setLoading(false);
}; }
- Verification:
- Click the “Fetch Reviews” button in the UI. Observe loading UI, then updated reviews and stats.
Exercise D — Error handling & loading UI (15m) - Goal: Add friendly error display and loading indicator - Add error
state and render an alert box when present. Add a spinner for loading
. - Instructor tip: show a simple tailwind or CSS snippet for visually obvious feedback.
Integration testing & verification
Run these checks (instructor asks students to perform or instructor demos):
- Backend health:
curl http://localhost:4000/health
- List reviews API:
curl http://localhost:4000/api/products/1/reviews
- Trigger fetch endpoint:
curl -X POST http://localhost:4000/api/products/1/fetch
- From browser: Click “Fetch Reviews”; open DevTools → Network and Console. Confirm:
- No CORS errors
- 200 responses from backend
- JSON with reviews and stats
- Database quick check (if they have CLI access):
# Example MySQL check (replace credentials as needed)
mysql -u root -p review_aggregator -e "SELECT COUNT(*) FROM reviews WHERE product_id=1;"
Common problems & quick fixes (triage guide for TAs)
- CORS error persists:
- Ensure
app.use(cors(...))
is before your routes and that the origin matches the frontend URL - Try temporarily allowing all origins for debugging:
app.use(cors())
then narrow down
- Ensure
- Frontend shows “Failed to fetch”:
- Check backend is actually running on port 4000 with
/health
- Inspect the Network tab to see the exact request URL
- Check backend is actually running on port 4000 with
- 404 on product id:
- Verify you’re using an existing product id in DB (use product 1 as default)
- Scraper returns no new reviews:
- That’s OK — the flow still validates connectivity. Point students to backend logs for scraper errors
Tests to include (quick & manual)
- Happy path: trigger scraper → fetch reviews → stats update
- Backend down: stop backend, confirm frontend shows a helpful error
- Invalid product id: attempt
productId=9999
and confirm 404 handling
Materials to distribute in Teams chat (paste these as files/snippets)
reviewsAPI.js
snippet (see above)app.use(cors...)
snippet (see above)handleFetchReviews
example (see above)- Verification curl commands (see Integration testing section)
- Short checklist for students to paste in their editors
Assessment & grading rubric (quick)
- 5 points: Backend CORS configured correctly (no CORS errors)
- 10 points: Frontend fetches real reviews (visible in UI)
- 5 points: Stats update correctly
- 5 points: Error handling and user feedback implemented
Wrap-up (last 5 minutes)
- Ask 2–3 students to briefly share their screens and demo success
- Collect common issues encountered and share fixes in chat
- Provide next steps: deploy to a PaaS, add auth, or add retries (optional homework)
Files referenced
- Lecture:
webdev_06_L_FullStackIntegration.qmd
- Practice:
webdev_06_P_FullStackIntegration.qmd
- New/edited student files:
frontend/src/api/reviewsAPI.js
, review component file (example:frontend/src/pages/ReviewAggregatorPage.jsx
), backend app file (e.g.,backend/src/app.js
)
Quick printable checklist (copy/paste for Teams chat)
- Backend:
cd backend && npm run dev
(listening on 4000) - Frontend:
cd frontend && npm run dev
(listening on 5173) - Set
frontend/.env
if you like:VITE_BACKEND_URL=http://localhost:4000
- Edit
backend/src/app.js
to add CORS and restart backend - Add
frontend/src/api/reviewsAPI.js
and update component imports - Click “Fetch Reviews” and verify UI + DB