Request Object

Difficulty: Intermediate

The Flask request object is a context-local proxy that gives you access to all data sent by the client in the current HTTP request. It is imported from flask and is available inside any view function without being passed as an argument. Understanding the request object is essential for building any Flask application that processes user input.

Flask's request object is actually a Werkzeug Request instance, wrapped in Flask's context-local system. This means that even though you import request as a global, each concurrent request gets its own isolated request object. This design pattern is called 'context locals' and is unique to Flask's approach to handling request data.

The request.args attribute is an ImmutableMultiDict containing the parsed query string parameters. For a URL like '/search?q=flask&page=2', request.args['q'] returns 'flask' and request.args['page'] returns '2' (as a string). Use request.args.get('key', default) for safe access that returns a default instead of raising a KeyError. The get method also accepts a type parameter for automatic conversion: request.args.get('page', 1, type=int).

The request.method attribute tells you which HTTP method was used (GET, POST, PUT, DELETE, etc.). The request.headers object provides access to HTTP request headers as a dict-like object. Headers are case-insensitive: request.headers['Content-Type'] and request.headers['content-type'] both work.

The request.url gives the full URL including scheme, host, path, and query string. Related attributes include request.base_url (without query string), request.host_url (scheme and host only), request.path (just the path), and request.url_root (scheme, host, and application root).

The request.remote_addr attribute provides the client's IP address. However, behind a reverse proxy (like Nginx), this will be the proxy's IP. Use the ProxyFix middleware or the X-Forwarded-For header to get the real client IP in production.

The request object also provides request.is_json (true if the content type is JSON), request.is_secure (true for HTTPS), request.content_type, request.content_length, and request.referrer (the page that linked to this request). The request.environ attribute gives raw access to the underlying WSGI environ dictionary.

For testing and working outside of request context, Flask provides a test_request_context() context manager. Inside it, the request object is available just as it would be during a real request.

Code examples

Accessing Query Parameters

from flask import Flask, request

app = Flask(__name__)

@app.route('/search')
def search():
    # /search?q=flask&page=2&limit=10
    query = request.args.get('q', '')
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 20, type=int)

    return {
        'query': query,
        'page': page,
        'limit': limit,
        'results': f'Searching for "{query}" (page {page})'
    }

request.args.get() safely retrieves query parameters with optional defaults and type conversion. The type parameter automatically converts '2' to int 2, returning the default if conversion fails.

Request Properties

from flask import Flask, request

app = Flask(__name__)

@app.route('/debug')
def debug_request():
    return {
        'method': request.method,
        'url': request.url,
        'base_url': request.base_url,
        'path': request.path,
        'host': request.host,
        'remote_addr': request.remote_addr,
        'content_type': request.content_type,
        'is_json': request.is_json,
        'is_secure': request.is_secure,
        'user_agent': request.user_agent.string,
        'referrer': request.referrer,
    }

The request object exposes dozens of useful properties. These give you full access to the HTTP request metadata including URLs, headers, client information, and content negotiation details.

Accessing Headers

from flask import Flask, request

app = Flask(__name__)

@app.route('/api/data')
def get_data():
    # Headers are case-insensitive
    auth_header = request.headers.get('Authorization', '')
    content_type = request.headers.get('Content-Type', 'text/html')
    accept = request.headers.get('Accept', '*/*')
    custom = request.headers.get('X-Custom-Header')

    # Check for Bearer token
    token = None
    if auth_header.startswith('Bearer '):
        token = auth_header[7:]

    return {
        'has_token': token is not None,
        'content_type': content_type,
        'accept': accept,
        'custom_header': custom,
    }

request.headers provides case-insensitive access to HTTP headers. Use .get() with a default to avoid KeyErrors for missing headers. Bearer token extraction from the Authorization header is a common pattern.

ImmutableMultiDict Methods

from flask import Flask, request

app = Flask(__name__)

@app.route('/multi')
def multi_values():
    # URL: /multi?tag=python&tag=flask&tag=web

    # get() returns the first value
    first_tag = request.args.get('tag')  # 'python'

    # getlist() returns ALL values
    all_tags = request.args.getlist('tag')  # ['python', 'flask', 'web']

    # to_dict() converts to regular dict (first values only)
    as_dict = request.args.to_dict()  # {'tag': 'python'}

    # to_dict(flat=False) preserves all values
    as_multi = request.args.to_dict(flat=False)  # {'tag': ['python', 'flask', 'web']}

    return {
        'first': first_tag,
        'all': all_tags,
        'dict': as_dict,
        'multi_dict': as_multi
    }

request.args is an ImmutableMultiDict that supports multiple values for the same key. Use getlist() for multi-value parameters like checkboxes or multi-select. to_dict(flat=False) preserves all values.

Key points

Concepts covered

request, Query Parameters, Headers, request.args, request.method, Context Locals