python app.pypython -m unittest -vThe app is deployed at this URL - https://pythonfullstack.onrender.com/
- Implemented client-side routing (SPA) to avoid full page reloads and make navigation instant.
- Used a threaded Python HTTP server and optimized static file serving to handle multiple requests efficiently.
- Loaded data only when required (lazy loading) and reused common API responses to reduce unnecessary database calls.
This mini full-stack project built with Python (backend) and Vanilla JavaScript + Tailwind (frontend).
This project helps you understand how real web apps work:
- routing
- APIs
- HTTP requests
- DOM manipulation
- state management
- modular JavaScript
- frontend–backend communication
- How a backend serves data over REST APIs
- How a frontend fetches that data and updates the UI
- How routing works in both frontend and backend
- How to organize files in a real project
- Single Page Application (SPA) basics
- Dynamic routing without page reload
- Importing JS modules
- Using Tailwind CSS for styling
- Using external CDNs: Google Fonts, Font Awesome, favicons
- DOM manipulation: creating elements, updating HTML, rendering tables
- Component structure (
Header,Footer,StudentForm,StudentTable) - Maintaining UI state (editing mode)
- Python HTTP server using
BaseHTTPRequestHandler - Routing logic (UI routes vs API routes)
- Serving static files manually
- Basic CRUD operations
- Returning JSON responses
- Handling errors and sending 404 pages
- Working with a SQLite database
pythonFullStack/
│
├── app.py # Starts the Python server
├── router.py # Handles API + UI routes
│
├── controllers/ # API logic (CRUD operations)
├── services/ # Database interaction
├── database/ # SQLite setup
│
├── frontend/
│ ├── pages/ # SPA HTML pages (home, students, docs)
│ ├── assets/
│ │ ├── css/ # Custom styles
│ │ ├── js/
│ │ │ ├── router/ # SPA router
│ │ │ ├── components/ # UI components
│ │ │ ├── controllers/ # Frontend business logic
│ │ │ ├── services/ # API calls
│ │ │ └── utils/ # Helper functions
│ │ └── favicon/ # Favicon (remote in our case)
│ └── env.js # Frontend config
│
└── students.db # SQLite database
- Browser loads
index.html(SPA shell) - SPA router loads the correct page into
<main id="app">
- Initializes form events
- Calls API to load all students
- Renders the list in a table
- JS collects form data
- Sends
POST /api/students - On success → reloads the list
- Updates the table without refreshing the page
- Edit → loads student into the form
- Delete → triggers
DELETE /api/students/:id - Table refreshes dynamically
- Controls SPA page navigation
- Updates URL without page reload
- Injects HTML into the
<main>container
- Handles form events
- Calls student API
- Controls loading spinner
- Manages editing state
- Contains all fetch() calls
- Talks to backend API
- Safe JSON parser to avoid crashes
Header– page navigationFooter– brandingStudentForm– Add/Edit UIStudentTable– renders the table rowsAlert– success messages
-
Splits routes into:
- UI routes (
/students,/home) - Static files (
/frontend/...) - API routes (
/api/students)
- UI routes (
-
Sends 404 for unknown paths
-
Prevents JSON errors and crashes
- Contains CRUD operations
- Reads/Writes to database
- Sends JSON responses
- SQL statements
- Helper functions
- Connects to SQLite
- TailwindCSS via CDN
- Google Fonts (Outfit)
- Font Awesome icons
- External favicon
- Clean layout with card-style design
python app.py
Visit:
http://localhost:8000
The backend is a lightweight Python server built WITHOUT frameworks. No Flask, no FastAPI — just raw Python.
This teaches students:
- how HTTP actually works
- how routing is handled manually
- how APIs process requests
- how data flows from browser → server → database
Perfect for understanding fundamentals.
- Uses Python's built-in
BaseHTTPRequestHandler - You handle
GET,POST,PUT,DELETEmanually - Great for learning how web servers work under the hood
-
You decide which URL goes to which function
-
Splits routes into:
- UI routes (serving HTML/JS/CSS)
- API routes (JSON responses)
- Static file routes (anything inside
/frontend)
- Simple file-based database (
students.db) - Stores all student data permanently
- No server setup required
Backend supports:
| HTTP Method | Path | What it Does |
|---|---|---|
| GET | /api/students |
Get all students |
| GET | /api/students/:id |
Get a single student |
| POST | /api/students |
Add a new student |
| PUT | /api/students/:id |
Update a student |
| DELETE | /api/students/:id |
Delete a student |
- Python returns JSON strings manually
- Browser reads JSON using
fetch()
- If a route does not exist → return 404
- If parsing errors happen → safe 404
- Prevents server crashes and 502 errors
backend/
├── app.py # Starts the server
├── router.py # Handles all HTTP routing
│
├── controllers/ # Business logic (API handlers)
│ └── students.py # CRUD functions
│
├── services/ # Database helpers
│ └── student_service.py
│
├── database/
│ ├── connection.py # Opens SQLite connection
│ └── queries.py # SQL functions
│
└── core/
├── static.py # Serves static files (HTML, CSS, JS)
├── middleware.py # Adds CORS headers
├── request.py # (Optional) request parsing
└── responses.py # Helpers for sending JSON & 404
Backend returns:
frontend/pages/index.html
That HTML loads:
- Tailwind CDN
- JS modules
- SPA router
Everything else (JS/CSS/images) is served by the backend through:
if path.startswith("/frontend/"):
serve_static(...)The browser now requests:
/frontend/assets/js/router/viewRouter.js
/frontend/assets/js/components/Header.html
/frontend/env.js
...
Backend serves all of these using the static file server.
The backend router distinguishes:
/
/home
/students
/docs
These always return:
index.html (SPA shell)
Everything under:
/frontend/
gets served as a file.
Only URLs beginning with:
/api/students
go to backend Python functions.
This separation is extremely important for SPAs.
Example: create_student()
Runs when the browser does:
fetch("/api/students", { method: "POST" })
Backend steps:
- Read request body (JSON)
- Convert into Python dictionary
- Insert into SQLite (
INSERT INTO students ...) - Send back success response
Example success JSON:
{"status": "ok"}- Opens a connection to SQLite
- Ensures the table exists
Contains SQL like:
SELECT * FROM students;
INSERT INTO students (name, email, course, year)Uses queries to fulfill API calls:
- Get all students
- Get one
- Add
- Update
- Delete
This clean separation teaches:
- controller = business logic
- service = database logic
- router = HTTP logic
Here’s what happens when user clicks "Add Student":
-
Frontend JS reads form values
-
Sends JSON to backend (
POST /api/students) -
Backend:
- Parses JSON
- Inserts record into database
- Responds with success
-
Frontend:
- Shows alert
- Reloads student list (
GET /api/students) - Renders table
This is the full loop of a real full-stack application.