Every interactive feature starts with reading what the client sent, safely and in the right place.
Inside a view, from flask import request gives you the current request. It is a global-looking object that always refers to the request being handled (how that works is an expert topic).
Where data lives:
request.args: the query string,?q=flask&page=2request.form: fields from an HTML form POSTrequest.get_json(): the parsed JSON bodyrequest.files: uploaded files, asFileStorageobjects with.filenameand.save()request.headers,request.cookies,request.method,request.path
args and form are MultiDicts: a key may appear more than once (?tag=a&tag=b). request.args.get("tag") returns the first value, getlist("tag") all of them.
Use .get() with a default and a type instead of indexing: request.args.get("page", 1, type=int) returns 1 for a missing or non-numeric value. Indexing a missing key, request.form["email"], raises KeyError, which Flask turns into 400 Bad Request. That is fine for required fields, but .get() gives you control over the message.
For JSON, request.get_json() returns 415 Unsupported Media Type if the Content-Type isn't application/json, and 400 if the body is malformed. get_json(silent=True) returns None instead.
Treat all of these as untrusted input. For anything non-trivial, validate with a library such as Pydantic or WTForms, and never trust file.filename: pass it through werkzeug.utils.secure_filename before saving.
Example
from flask import Flask, request
app = Flask(__name__)
@app.get("/search")
def search():
q = request.args.get("q", "")
page = request.args.get("page", 1, type=int)
tags = request.args.getlist("tag")
return {"q": q, "page": page, "tags": tags}
@app.post("/notes")
def add_note():
data = request.get_json()
return {"saved": data["text"], "agent": request.headers.get("User-Agent")}
c = app.test_client()
print(c.get("/search?q=flask&page=x&tag=a&tag=b").json)
# {'page': 1, 'q': 'flask', 'tags': ['a', 'b']}
print(c.post("/notes", json={"text": "hi"}).json["saved"]) # hi
print(c.post("/notes", data="hi").status_code) # 415Remember
- request.args = query string, request.form = form body, get_json() = JSON body
- Use .get(key, default, type=int) and .getlist() on MultiDicts
- A missing key via [] becomes a 400 Bad Request
Watch out for
- Looking for POSTed form fields in request.args, or JSON in request.form.