After yesterday's backend success, today was about making my React frontend actually TALK to my Node.js API.
Spoiler alert: It wasn't as simple as I thought. But that's where the real learning happened.
What I Set Out to Do Today
Build a React frontend that:
- ✅ Connects to my backend API
- ✅ Fetches health status automatically
- ✅ Displays users from the database
- ✅ Shows everything in a nice UI
Simple, right? Well... let me share the journey.
Step 1: Creating the React App
I started by creating a React app in my project folder:
cd ~/Desktop/Production-Ready-Microservices-Platform
npx create-react-app frontend
This created a complete React application with all the boilerplate code.
What I learned: create-react-app is a magical command that sets up an entire React development environment in minutes. It includes:
- Development server with hot reloading
- Build tools (webpack, Babel)
- Testing setup
- Production build optimization
Step 2: Cleaning Up Unnecessary Files
React creates many example files. I removed what I didn't need:
cd frontend/src
rm App.test.js setupTests.js reportWebVitals.js logo.svg
What I learned: reportWebVitals.js tracks performance metrics (load time, responsiveness). Not needed for learning, but useful for production apps.
Oops moment: After deleting files, React crashed because index.js was still trying to import reportWebVitals. Fixed by removing those import lines from index.js.
Step 3: Writing the React Component
Here's the complete App.js I built:
import { useState, useEffect } from 'react';
import './App.css';
function App() {
// State = memory for our component
const [backendStatus, setBackendStatus] = useState('Checking backend...');
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
// useEffect = runs automatically when page loads
useEffect(() => {
checkBackendHealth();
}, []);
// Check if backend is alive
async function checkBackendHealth() {
try {
const response = await fetch('http://localhost:8000/health');
const data = await response.json();
setBackendStatus(`✅ Backend is healthy! Service: ${data.service}`);
} catch (error) {
setBackendStatus('❌ Cannot reach backend. Make sure it\'s running on port 8000');
}
}
// Load users from backend
async function loadUsers() {
setLoading(true);
try {
const response = await fetch('http://localhost:8000/users');
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Failed to load users:', error);
} finally {
setLoading(false);
}
}
return (
<div className="App">
<h1> Microservices Platform</h1>
<div className="status-card">
<h2>Backend Status</h2>
<p>{backendStatus}</p>
</div>
<div className="status-card">
<h2> Users List</h2>
<button onClick={loadUsers} disabled={loading}>
{loading ? 'Loading...' : 'Load Users'}
</button>
<div className="users-list">
{users.map(user => (
<div key={user.id} className="user-item">
<strong>{user.name}</strong>
<br />
{user.email}
</div>
))}
</div>
</div>
</div>
);
}
export default App;
The Major Problem: CORS
I ran both servers:
- Backend on port 8000 (
npm run dev) - Frontend on port 3000 (
npm start)
But my React app showed: ❌ Cannot reach backend
The browser console showed this error:
Access to fetch at 'http://localhost:8000/health' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
What is CORS? (Simple Explanation)
| Term | Meaning |
|---|---|
| CORS | Cross-Origin Resource Sharing |
| Origin | The domain + port where your app lives (http://localhost:3000) |
| The Problem | Browsers block requests from one origin to another by default (security) |
| The Fix | Tell the backend "It's OK to accept requests from React" |
Analogy:
- React = A person at door 3000
- Backend = A person at door 8000
- Browser = Security guard
- Without CORS = Guard says "You can't talk to each other, different doors!"
- With CORS = Guard says "Oh, it's allowed. Go ahead!"
Fixing CORS (Step by Step)
Step 1: Install the CORS package
cd backend
npm install cors
Step 2: Add CORS to server.js
const express = require('express');
const cors = require('cors'); // ← ADD THIS
const app = express();
app.use(cors()); // ← ADD THIS
Step 3: Restart both servers
- Backend:
Ctrl+Cthennpm run dev - Frontend:
Ctrl+Cthennpm start
Step 4: Hard refresh browser
Ctrl + Shift + R
The Moment It Worked
After fixing CORS, my browser showed:
Backend Status: ✅ Backend is healthy! Service: backend-api
Clicking "Load Users" displayed:
- Alice (alice@example.com)
- Bob (bob@example.com)
- Charlie (charlie@example.com)
SUCCESS! My frontend and backend were finally talking!
Key Learnings from Day 3
Technical Concepts
| Concept | What I Learned |
|---|---|
| React State |
useState creates memory for your component. When state changes, UI updates automatically |
| useEffect | Runs code automatically when component loads (great for fetching initial data) |
| fetch API | Browser's built-in way to make HTTP requests to APIs |
| CORS | Browser security that blocks cross-origin requests unless backend allows it |
| Ports | React uses 3000, backend uses 8000 — different ports = different origins |
Problem-Solving Skills
- Reading error messages: The CORS error looked scary, but it told me exactly what was wrong
-
Using browser Console:
F12→ Console tab shows all errors -
Testing with curl:
curl http://localhost:8000/healthproved backend was working (curl ignores CORS) - Systematic debugging: Backend works? Yes. Frontend works? Yes. Connection? CORS issue.
Mistakes I Made (And Fixed)
| Mistake | Consequence | Fix |
|---|---|---|
| Deleted files without updating imports | React compilation error | Removed import lines from index.js |
| Didn't install CORS package | CORS still blocked | npm install cors |
| Forgot to restart backend | Changes didn't take effect |
Ctrl+C then npm run dev
|
| Didn't hard refresh browser | Saw old cached page | Ctrl+Shift+R |
Tips for Anyone Building Their First React + API App
- Test backend with curl first — If curl works but React doesn't, it's CORS
- Always restart servers after changes — They don't auto-reload config
- Use browser Console — It's your best friend for debugging
- Hard refresh (Ctrl+Shift+R) — Avoid seeing cached old versions
- Keep both terminals visible — One for backend, one for frontend
Resources
Let's Connect!
Have you struggled with CORS before? Building your first full-stack app? I'd love to hear about your journey!
Drop a comment or connect on LinkedIn. Let's learn together!
This is Day 3 of my 30-Day Cloud & DevOps Challenge. Follow along as I build a complete microservices platform from scratch!
Top comments (0)