061
LVL 03 — MID DEVELOPERSESSION 061DAY 61

FRONTEND ↔ BACKEND

🎫 PIXELCRAFT-048
Feature | 🟡 Medium | Priority: 🔴 Critical

The React frontend still uses localStorage for everything. Connect it to the Express API. Gallery loads from the server. CRUD operations work end-to-end.
CONCEPTS.UNLOCKED
🔌
fetch() API in React
GET, POST, PUT, DELETE with proper headers. The bridge between React and Express. Send requests, receive JSON, update the UI. The same fetch you learned in Session 28, now with auth.
🌐
CORS
Cross-Origin Resource Sharing. Your React app (localhost:5173) and API (localhost:3001) are different origins. The browser blocks cross-origin requests by default. CORS headers allow them.
🎫
Auth Token Management
Store token, send with every request. localStorage stores the JWT. Every API call includes Authorization: Bearer <token>. Expired token → redirect to login.
🔄
Loading / Error / Success States
Every API call has three states: loading (show spinner), error (show message + retry), success (show data). Handle all three or the UI breaks.
Environment Variables
VITE_API_URL for different environments. Development: localhost:3001. Production: api.pixelcraft.com. Same code, different config.
🧰
API Utility Function
One reusable function that handles: base URL, auth headers, JSON parsing, error extraction. Every component calls api('/path') instead of raw fetch.
HANDS-ON.TASKS
01
Create an API Utility
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001'; async function api(path, options = {}) { const token = localStorage.getItem('token'); const res = await fetch(`${API_URL}${path}`, { ...options, headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), ...options.headers, }, }); if (!res.ok) { const error = await res.json() .catch(() => ({ error: 'Request failed' })); throw new Error( error.error || `HTTP ${res.status}` ); } if (res.status === 204) return null; return res.json(); } // Usage: const images = await api('/api/images'); await api('/api/images', { method: 'POST', body: JSON.stringify(imageData) }); await api(`/api/images/${id}`, { method: 'DELETE' });
02
Build Gallery with Loading/Error States
function Gallery() { const [images, setImages] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { api('/api/images') .then(setImages) .catch(err => setError(err.message)) .finally(() => setLoading(false)); }, []); if (loading) return <Spinner />; if (error) return <ErrorMessage message={error} onRetry={() => window.location.reload()} />; if (images.length === 0) return <EmptyState message="No images yet. Upload your first!" />; return ( <div className="grid grid-cols-4 gap-4 p-4"> {images.map(img => ( <ImageCard key={img._id} image={img} /> ))} </div> ); }
03
Test Full Flow

Register → login → upload image metadata → see it in gallery → delete it. End-to-end CRUD working.

04
Handle Token Expiration

When the API returns 401, redirect to login. Clear the expired token. Show a toast: "Session expired. Please log in again."

05
Close the Ticket
git switch -c feature/PIXELCRAFT-048-connect-frontend git add src/ server/ git commit -m "Connect React frontend to Express API (PIXELCRAFT-048)" git push origin feature/PIXELCRAFT-048-connect-frontend # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

CORS (Cross-Origin Resource Sharing).

The same-origin policy is a security measure. CORS headers explicitly allow cross-origin requests.

// The security model:

React app     → localhost:5173
Express API   → localhost:3001

Different origins → browser blocks
  by default (same-origin policy)

CORS headers → server says
  "I allow requests from this origin"

// This prevents malicious websites from
// making requests to your bank's API
// using your cookies.
"Full-Stack Lab"
[A]Add an axios interceptor (or modify the api utility) that automatically retries failed requests once before showing an error. Handle network failures gracefully.
[B]Add optimistic UI: when deleting an image, remove it from the gallery immediately, then send the DELETE request. If it fails, add it back and show an error.
[C]Add a "network status" indicator: show a banner when the user goes offline. Queue operations and replay them when back online. Research the navigator.onLine API.
REF.MATERIAL
ARTICLE
Mozilla Developer Network
Complete fetch reference: GET, POST, headers, body, error handling, and streaming responses.
FETCHMDNESSENTIAL
ARTICLE
Mozilla Developer Network
How CORS works: preflight requests, allowed headers, credentials, and common error debugging.
CORSSECURITYMDN
VIDEO
Fireship
Ultra-fast CORS explanation: same-origin policy, preflight requests, and how to configure CORS correctly.
CORSQUICK
ARTICLE
Vite Team
Environment variables in Vite: VITE_ prefix, .env files, mode-specific configs, and accessing in code.
VITEENVOFFICIAL
VIDEO
Traversy Media
Complete React + Express tutorial: connecting frontend to backend, auth flow, CRUD operations, and deployment.
FULL-STACKTUTORIAL
// LEAVE EXCITED BECAUSE
Frontend talks to backend! Gallery loads from the database. Login works. CRUD is end-to-end. PixelCraft is a real full-stack web application.