Project 1~45 minutesWorked Example

Hello Full-Stack

Interview Scenario: "Let's start simple. Can you set up a basic full-stack app where the frontend displays a greeting message fetched from the backend?"

What You'll Learn

  • Project structure for both Next.js and FastAPI
  • CORS configuration (critical!)
  • Basic fetch() from React to Python
  • The useEffect + useState pattern for data fetching
Loading...

Step 1: The FastAPI Backend

If you followed the setup guide, you already have a backend folder. Let's expand it:

backend/main.py
1from fastapi import FastAPI
2from fastapi.middleware.cors import CORSMiddleware
3
4app = FastAPI()
5
6# THIS IS CRITICAL - without this, your frontend cannot call your backend
7app.add_middleware(
8 CORSMiddleware,
9 allow_origins=["http://localhost:3000"], # Your Next.js app
10 allow_credentials=True,
11 allow_methods=["*"], # Allow all HTTP methods
12 allow_headers=["*"], # Allow all headers
13)
14
15@app.get("/")
16def read_root():
17 return {"message": "Hello from FastAPI!"}
18
19@app.get("/api/greeting/{name}")
20def get_greeting(name: str):
21 return {"greeting": f"Hello, {name}! Welcome to full-stack development."}

CORS is the #1 gotcha

Always add CORS middleware IMMEDIATELY after creating your FastAPI app. Forgetting CORS is the most common reason full-stack apps fail to connect. If asked "why isn't my frontend getting data?", CORS should be your first thought.

Run the backend:

Terminal 1
1uvicorn main:app --reload --port 8000
2
3# Visit http://localhost:8000/docs to see auto-generated API docs!

Step 2: The Next.js Frontend

frontend/app/page.tsx
1"use client" // THIS IS REQUIRED for useState/useEffect
2
3import { useState, useEffect } from "react"
4
5export default function Home() {
6 const [greeting, setGreeting] = useState<string>("")
7 const [loading, setLoading] = useState<boolean>(true)
8 const [name, setName] = useState<string>("")
9
10 // Fetch initial greeting on page load
11 useEffect(() => {
12 fetch("http://localhost:8000/")
13 .then(res => res.json())
14 .then(data => {
15 setGreeting(data.message)
16 setLoading(false)
17 })
18 .catch(err => {
19 setGreeting("Error connecting to backend")
20 setLoading(false)
21 })
22 }, []) // Empty array = run once on mount
23
24 // Fetch personalized greeting
25 const fetchPersonalGreeting = async () => {
26 if (!name) return
27 const res = await fetch(`http://localhost:8000/api/greeting/${name}`)
28 const data = await res.json()
29 setGreeting(data.greeting)
30 }
31
32 return (
33 <main className="min-h-screen p-8">
34 <h1 className="text-3xl font-bold mb-4">Full-Stack Hello</h1>
35
36 {loading ? (
37 <p>Loading...</p>
38 ) : (
39 <p className="text-xl mb-6">{greeting}</p>
40 )}
41
42 <div className="flex gap-2">
43 <input
44 type="text"
45 value={name}
46 onChange={(e) => setName(e.target.value)}
47 placeholder="Enter your name"
48 className="border p-2 rounded"
49 />
50 <button
51 onClick={fetchPersonalGreeting}
52 className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
53 >
54 Get Personal Greeting
55 </button>
56 </div>
57 </main>
58 )
59}

Understanding the Code

"use client" directive

Next.js 13+ uses Server Components by default. Adding "use client" makes the component run in the browser, which is required for useState, useEffect, and event handlers like onClick.

useEffect with empty dependency array []

This pattern means "run this code once when the component first appears." Perfect for initial data fetching. If you put a variable in the array like [userId], it re-runs whenever that variable changes.

The loading state pattern

Always track loading state. Users should never see a blank screen. This is a small detail that shows interviewers you think about user experience.

Exercises

What You Learned

FastAPI

  • Basic route structure (@app.get)
  • Path parameters (/greeting/{name})
  • CORS configuration

Next.js/React

  • 'use client' directive
  • useState for component state
  • useEffect for side effects
  • Basic fetch() with async/await

Ready for more?

In the next project, you'll build a full CRUD application with a real database.

Project 2: Task Tracker