Full-Stack Integration — Teams Practical

Connect React Frontend with Express Backend (Teams Session)

full-stack
integration
CORS
Practical
Auteur
Affiliations

Université de Toulon

LIS UMR CNRS 7020

Date de publication

2025-10-11

Résumé

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)

  1. Clone repository and checkout their working branch
  2. Have the backend running: cd backend && npm run dev (should listen on port 4000)
  3. Have the frontend running: cd frontend && npm run dev (should be on port 5173)
  4. Have MySQL available and accessible by the backend, with sample data for product id 1
  5. 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

  1. Show CORS problem quickly: open browser console and attempt a fetch from frontend to backend without CORS configured.
  2. Explain CORS origin concept and why Express must explicitly allow the frontend origin.
  3. Show the minimal CORS fix in backend/src/app.js (or server.js):
// backend/src/app.js
const cors = require('cors');

app.use(cors({
  origin: 'http://localhost:5173',
  credentials: true
}));

// Make sure this is placed BEFORE your route handlers
  1. Explain environment variables in the frontend (Vite): VITE_BACKEND_URL=http://localhost:4000 and how to use import.meta.env.VITE_BACKEND_URL.
  2. 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):

  1. Backend health:
curl http://localhost:4000/health
  1. List reviews API:
curl http://localhost:4000/api/products/1/reviews
  1. Trigger fetch endpoint:
curl -X POST http://localhost:4000/api/products/1/fetch
  1. From browser: Click “Fetch Reviews”; open DevTools → Network and Console. Confirm:
    • No CORS errors
    • 200 responses from backend
    • JSON with reviews and stats
  2. 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
  • 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
  • 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)

  1. Backend: cd backend && npm run dev (listening on 4000)
  2. Frontend: cd frontend && npm run dev (listening on 5173)
  3. Set frontend/.env if you like: VITE_BACKEND_URL=http://localhost:4000
  4. Edit backend/src/app.js to add CORS and restart backend
  5. Add frontend/src/api/reviewsAPI.js and update component imports
  6. Click “Fetch Reviews” and verify UI + DB

Réutilisation