Form + Fetch + FastAPI Backend
A login form that POSTs to FastAPI, a button that GETs users, and a live clock — the exact pattern behind every auth flow.
🚀 Mini Project · 3 filesProject files
<!DOCTYPE html>
<html>
<head><title>Sign In</title></head>
<body>
<form method='post' action='http://127.0.0.1:8000/signin' enctype='multipart/form-data'>
<input type='text' name='username' placeholder='Name'>
<input type='number' name='id' placeholder='ID'>
<input type='file' name='file'>
<button id='login'>Login</button>
<a href='http://127.0.0.1:8000/get-users'>Retrieve Users</a>
</form>
<h5 id='sample'>User data will appear here</h5>
<button id='g1'>Click To Get</button>
<input id='g2' placeholder='type something'>
<h3 id='g3'>YOUR INPUT</h3>
<h3 id='clock'>Clock</h3>
<script>
// Live clock — update every second
setInterval(() => {
document.getElementById('clock').textContent = new Date().toLocaleTimeString();
}, 1000);
// Live input mirror — fires on every keystroke
document.getElementById('g2').addEventListener('input', (e) => {
document.getElementById('g3').textContent = e.target.value;
});
// Fetch users from FastAPI
document.getElementById('g1').addEventListener('click', async (e) => {
e.preventDefault();
const res = await fetch('http://127.0.0.1:8000/get-users');
const data = await res.json();
const u = data[0];
document.getElementById('sample').innerHTML =
'<p>' + u.username + ' : ' + u.id + '</p>';
});
</script>
</body>
</html>
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import uvicorn, shutil, os
app = FastAPI()
# Allow the browser to call this API from a different origin (file://)
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['*'],
allow_headers=['*'],
)
# In-memory user store (use a DB in real apps)
USERS = [
{'id': 1, 'username': 'Ada'},
{'id': 2, 'username': 'Linus'},
]
@app.get('/get-users')
async def get_users():
return USERS
@app.post('/signin')
async def signin(
username: str = Form(...),
id: int = Form(...),
file: UploadFile = File(...),
):
# Save uploaded file
os.makedirs('uploads', exist_ok=True)
with open(f'uploads/{file.filename}', 'wb') as f:
shutil.copyfileobj(file.file, f)
USERS.append({'id': id, 'username': username})
return {'status': 'ok', 'user': username, 'file': file.filename}
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=8000)
# Install FastAPI + uvicorn pip install fastapi uvicorn python-multipart # Run the server python main.py # Open index.html in a browser (double-click the file) # Try: type a name in the form, upload a file, click Login # Then click 'Click To Get' to see the user list
How it works
This is the foundational full-stack pattern. Step by step: (1) The HTML form collects username + id + file. method='post' sends it to /signin. enctype='multipart/form-data' is REQUIRED because the form has a file input — without it, the upload silently fails. (2) FastAPI's @app.post('/signin') receives the form fields via Form(...) and the file via UploadFile. shutil.copyfileobj streams the file to disk without loading it all into memory. (3) The 'Click To Get' button calls fetch('http://127.0.0.1:8000/get-users') which returns JSON. await res.json() parses it. (4) setInterval updates the clock every 1000ms. (5) The 'input' event listener mirrors the text field into the <h3> on every keystroke. CORS middleware is needed because the browser loads index.html from file:// but calls the API at http://127.0.0.1:8000 — different origins. Without CORS, the browser blocks the request.
⚡ Open in Notebook