A simple learning-management app that lets developers track the courses they want to learn.
- Part 1 (Option B): REST API built with Python + Flask
- Part 2: single-file CRUD dashboard (
index.html) built with vanilla HTML, CSS, and JavaScript
Course data is stored in a plain JSON text file (courses.json) - no database
required. CORS is enabled so the Part 2 dashboard can call the API from a
browser.
- Full CRUD over
/api/courses(Create, Read, Update, Delete) - Flat-file JSON storage, created automatically if missing
- Input validation: required fields,
YYYY-MM-DDdate format, and a fixedstatusenum (Not Started,In Progress,Completed) - Consistent JSON responses (
success,error,message) and correct HTTP status codes - CORS enabled for all routes
- Bonus endpoints:
/api/courses/statsand/api/courses/search - Pytest test suite (
test_app.py) - Single-file dashboard UI (
index.html) - no build step, no frameworks
codecrafthub/
├── app.py # Flask application (all endpoints + helpers)
├── index.html # Part 2: single-file CRUD dashboard (HTML + CSS + JS)
├── courses.json # JSON data store (sample data included; auto-created if deleted)
├── requirements.txt # Python dependencies
├── test_app.py # Pytest test suite
├── .gitignore
└── README.md
- Python 3.8+
pipcurl(for manual testing)- Git (optional, for pushing to GitHub)
cd codecrafthub
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtpython app.pyYou should see:
============================================================
CodeCraftHub API is starting...
============================================================
Data will be stored in: /path/to/codecrafthub/courses.json
API will be available at: http://localhost:5000
============================================================
The API is now live at http://localhost:5000.
Port 5000 already in use? On macOS the AirPlay Receiver service claims it. Either turn that off (System Settings → General → AirDrop & Handoff) or run on another port:
PORT=5001 python app.py(then usehttp://localhost:5001in the curl commands and in your Part 2 dashboard base URL).
All responses are JSON. Successful responses include "success": true; errors
include "success": false and an "error" message.
{
"id": 1,
"name": "Python Basics",
"description": "Learn Python fundamentals",
"target_date": "2026-12-31",
"status": "Not Started",
"created_at": "2026-09-10 14:05:33"
}status must be one of: Not Started, In Progress, Completed.
| Method | Path | Description | Success code |
|---|---|---|---|
| GET | / |
API info / endpoint list | 200 |
| GET | /api/courses |
List all courses | 200 |
| GET | /api/courses/<id> |
Get one course | 200 |
| POST | /api/courses |
Create a course | 201 |
| PUT | /api/courses/<id> |
Update a course (any subset of fields) | 200 |
| DELETE | /api/courses/<id> |
Delete a course | 200 |
| GET | /api/courses/stats |
Counts by status | 200 |
| GET | /api/courses/search?q=<term> |
Search name + description | 200 |
Error codes used: 400 (bad/missing input), 404 (course or route not found),
405 (wrong method), 500 (file read/write failure).
Make sure the server is running, then in a second terminal:
Create a course (POST)
curl -X POST http://localhost:5000/api/courses \
-H "Content-Type: application/json" \
-d '{
"name": "Python Basics",
"description": "Learn Python fundamentals",
"target_date": "2026-12-31",
"status": "Not Started"
}'Get all courses (GET)
curl http://localhost:5000/api/coursesGet one course (GET)
curl http://localhost:5000/api/courses/1Update a course (PUT)
curl -X PUT http://localhost:5000/api/courses/1 \
-H "Content-Type: application/json" \
-d '{ "status": "In Progress" }'Delete a course (DELETE)
curl -X DELETE http://localhost:5000/api/courses/1Statistics (bonus)
curl http://localhost:5000/api/courses/statsSearch (bonus)
curl "http://localhost:5000/api/courses/search?q=python"Verify that:
- Each endpoint returns the expected status code and JSON body
- Data persists in
courses.jsonbetween requests - Invalid input returns
400, unknown ids return404
index.html is a self-contained dashboard - all HTML, CSS, and JavaScript live
in that one file. There is no build step and no framework; just open it.
- Start the backend (see above) and leave it running.
- Open
index.htmlin your browser (double-click it, oropen index.htmlon macOS).
The dashboard talks to http://localhost:5000/api/courses by default. If your
server is on a different port, edit the Backend API box in the purple header
and click Reconnect - the choice is remembered next time you open the page.
(The default is also set by DEFAULT_API_BASE near the top of the <script>
block.)
| Feature | Backend call |
|---|---|
| Course cards with status badges | GET /api/courses |
| "Add a New Course" form | POST /api/courses |
| Edit button → modal dialog | PUT /api/courses/<id> |
| Remove button → confirm prompt | DELETE /api/courses/<id> |
It also handles loading spinners, success/error toasts, required-field validation before submitting, and a responsive single-column layout on phones.
- Confirm the backend is actually running (
curl http://localhost:5000/api/courses). - Confirm the port in the Backend API box matches the port the server printed.
- CORS is already enabled in
app.pyviaCORS(app); if requests are still blocked, check thatFlask-Corsinstalled correctly.
pytest -vThe tests run against a temporary data file, so your real courses.json is
never modified.
| Problem | Fix |
|---|---|
ModuleNotFoundError: No module named 'flask' |
Activate the venv and run pip install -r requirements.txt |
Address already in use on port 5000 |
Stop the other process, or change PORT in app.py. On macOS, port 5000 can be taken by AirPlay Receiver (System Settings → General → AirDrop & Handoff). |
| Dashboard calls blocked by CORS | Confirm the server is running and Flask-Cors is installed; CORS(app) in app.py allows all origins. |
courses.json got corrupted |
Delete it; the app recreates an empty one on the next request. |
| Changes not saving | Check file permissions on the codecrafthub directory. |
cd codecrafthub
git init
git add .
git commit -m "Complete CodeCraftHub backend (Python + Flask)"
git branch -M main
git remote add origin <your-github-repo-url>
git push -u origin mainUse a GitHub Personal Access Token as the password when prompted.