The Request Object

Introduction

Every HTTP request arrives as Flask’s request proxy—query strings, form fields, JSON bodies, headers, cookies, and client metadata. This chapter shows how to read each part safely and notes proxy headers when your app sits behind Nginx.

Prerequisites

Import and Basics

python
from flask import Flask, request
 
app = Flask(__name__)
 
@app.route("/debug-request", methods=["GET", "POST"])
def debug_request():
    return {
        "method": request.method,
        "path": request.path,
        "content_type": request.content_type,
    }

Code explanation:

  • request is thread-local—safe in sync views under WSGI
  • Only valid inside a request context (view, before_request, etc.)

Query String: request.args

URL: /search?q=flask&page=2

python
@app.route("/search")
def search():
    q = request.args.get("q", "")
    page = request.args.get("page", 1, type=int)
    return f"Search: {q}, page {page}"

Code explanation:

  • request.args is like a dict of query parameters
  • type=int converts or returns None if invalid

Multiple values:

python
tags = request.args.getlist("tag")

Form Data: request.form

HTML form POST:

python
@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form.get("username", "")
        password = request.form.get("password", "")
        return f"Hello, {username}"
    return '<form method="post"><input name="username"><button>Go</button></form>'

Use request.form for application/x-www-form-urlencoded and multipart/form-data (non-file fields).

JSON Body: request.get_json()

Client sends Content-Type: application/json:

python
@app.route("/api/items", methods=["POST"])
def create_item():
    data = request.get_json(silent=True)
    if not data:
        return {"error": "JSON required"}, 400
    name = data.get("name")
    return {"created": name}, 201

Test:

bash
curl -X POST http://127.0.0.1:5000/api/items \
  -H "Content-Type: application/json" \
  -d '{"name":"widget"}'

Code explanation:

  • silent=True avoids exception on bad JSON—returns None
  • force=True parses body even without JSON content type (use carefully)

Headers and Cookies

python
@app.route("/headers-demo")
def headers_demo():
    user_agent = request.headers.get("User-Agent", "")
    auth = request.headers.get("Authorization")
    session_id = request.cookies.get("session_id")
    return {"ua": user_agent, "auth": bool(auth), "session": session_id}

Custom headers for APIs:

bash
curl -H "Authorization: Bearer TOKEN" http://127.0.0.1:5000/headers-demo

Files: request.files (Preview)

python
from flask import Flask, request
 
@app.route("/upload", methods=["POST"])
def upload():
    file = request.files.get("photo")
    if not file or file.filename == "":
        return "No file", 400
    return f"Received {file.filename}"

Full upload chapter covers validation and storage.

Client IP and Proxies

python
@app.route("/who")
def who():
    return {"remote_addr": request.remote_addr}

Behind Nginx, remote_addr may be 127.0.0.1. Trust proxy config:

python
from werkzeug.middleware.proxy_fix import ProxyFix
 
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)

Then read request.access_route or configured forwarded headers—only when you control the proxy.

Tip

Trust Proxies Deliberately

Misconfigured ProxyFix lets clients spoof IP—enable only behind your load balancer.

Request vs Global State

Do not store request data in global variables across requests—use g (later chapter) for per-request app state.

FAQ

request.form empty on POST?

Check method="post", Content-Type, and that you read form not json.

get_json returns None?

Missing body, wrong content type, or invalid JSON—inspect with request.data.

Unicode in query args?

Flask decodes UTF-8 query strings—ensure client encodes properly.

CSRF on forms?

Raw HTML forms need CSRF tokens—Flask-WTF chapter covers this.

Large JSON payloads?

Configure MAX_CONTENT_LENGTH in config to reject huge bodies.

request.json vs get_json?

request.json property may raise; get_json(silent=True) is safer in APIs.