Forms, sessions and errors
Reading request data, validating it, flashing messages, keeping a session, and returning sensible error responses.
Reading the request
from flask import request, abort, redirect, url_for, flash, session
@app.post("/subscribe")
def subscribe():
email = request.form.get("email", "").strip()
if "@" not in email:
flash("Enter a valid email address", "error")
return redirect(url_for("index"))
page = request.args.get("page", 1, type=int) # query string, cast
payload = request.get_json(silent=True) or {} # JSON body, no 400 on bad JSON
ua = request.headers.get("User-Agent", "")
return {"email": email, "page": page}| Source | Accessor |
|---|---|
| Form body | request.form |
| Query string | request.args |
| JSON body | request.get_json() |
| Uploaded files | request.files |
| Cookies / headers | request.cookies / request.headers |
⚠️
Every value from the client is untrusted text. Validate type, length and range on the server — HTML form attributes are a convenience, not a control.
Sessions and messages
@app.post("/login")
def login():
if not check_credentials(request.form["user"], request.form["pw"]):
abort(401)
session.clear() # prevent session fixation
session["uid"] = 7
return redirect(url_for("dashboard"))
@app.get("/dashboard")
def dashboard():
if "uid" not in session:
return redirect(url_for("login"))
return render_template("dashboard.html")Flask's default session is a signed cookie: the client can read it but not modify it. Anything secret or large belongs in a server-side store keyed by a session id.
Errors and API responses
@app.errorhandler(404)
def not_found(err):
if request.path.startswith("/api/"):
return {"error": "not found"}, 404
return render_template("404.html"), 404
@app.errorhandler(500)
def server_error(err):
app.logger.exception("unhandled error")
return {"error": "internal error"}, 500
from flask import jsonify
return jsonify(ok=True), 201💡
Return the correct status code with the body:
200 with {"error": ...} forces every client to parse JSON to learn that something failed.FAQ
How do I keep the user's input in the form after an error?
Re-render the template with the submitted values, or use the
flash pattern with a redirect and have the form read from the session.Where do I put CSRF protection?
Use Flask-WTF (or an equivalent) and include the token in every state-changing form. Flask itself does not add CSRF tokens automatically.
Related
Templates with Jinja2 Forms, sessions and safety
Last refreshed 2026-09-18.