Skillversitas

Rendering HTML Forms

Form-based flows (login, contact, settings) need a page to render the form and an endpoint to handle the POST. The pattern: GET renders the template with initial values, POST receives Form fields, validates them, and redirects back (or renders an error) - the classic Post/Redirect/Get flow.

The Form Template

<!doctype html>
<html>
  <body>
    <h1>Subscribe</h1>
    {% if error %}<p class="error">{{ error }}</p>{% endif %}
    <form method="post" action="/subscribe">
      <label>Email <input name="email" value="{{ email | default('') }}" required /></label>
      <label>Plan
        <select name="plan">
          <option value="free">Free</option>
          <option value="pro">Pro</option>
        </select>
      </label>
      <button>Submit</button>
    </form>
  </body>
</html>

GET and POST Endpoints

from fastapi import FastAPI, Form, Request
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/subscribe")
def subscribe_page(request: Request):
    return templates.TemplateResponse("subscribe.html", {"request": request})

@app.post("/subscribe")
def subscribe_submit(
    request: Request,
    email: str = Form(),
    plan: str = Form("free"),
):
    if not email or "@" not in email:
        return templates.TemplateResponse(
            "subscribe.html",
            {"request": request, "error": "Valid email required", "email": email},
            status_code=422,
        )
    # save the subscription
    return RedirectResponse("/thanks", status_code=303)

Post/Redirect/Get

After a successful POST, redirect (303) to a confirmation page instead of re-rendering the form. If the user refreshes, the browser re-GETs the confirmation page rather than re-submitting the form - no duplicate submissions.

A Word on CSRF

For state-changing forms behind a session cookie, add a hidden token field the server validates on POST. Without a session (pure JSON APIs), CSRF is less of a concern because the browser does not attach credentials automatically.

Summary

Build form flows with a GET endpoint that renders the template and a POST endpoint that reads Form fields, validates them, and either re-renders with errors or redirects to a confirmation page. Use Post/Redirect/Get to prevent duplicate submissions, and add a CSRF token when the app relies on session cookies.