Skip to main content

Overview

Flask provides Request and Response objects that wrap Werkzeug’s WSGI request and response handling with Flask-specific enhancements.

Request Object

The request object is a global proxy that provides access to incoming request data.

Accessing Request Data

from flask import Flask, request

app = Flask(__name__)

@app.route('/search')
def search():
    # Query parameters
    query = request.args.get('q', '')
    page = request.args.get('page', 1, type=int)
    
    # Form data (POST)
    username = request.form.get('username')
    
    # JSON data
    data = request.get_json()
    
    # Headers
    user_agent = request.headers.get('User-Agent')
    
    # Cookies
    session_id = request.cookies.get('session_id')
    
    return jsonify({'query': query, 'page': page})

Request Properties

From wrappers.py:18-54, the Flask Request class provides:
# URL information
request.url           # Full URL
request.base_url      # URL without query string
request.url_root      # Root URL
request.path          # Path portion
request.query_string  # Raw query string (bytes)

# Method and routing
request.method        # HTTP method (GET, POST, etc.)
request.endpoint      # Matched endpoint name
request.view_args     # URL parameter dict
request.url_rule      # Matched Rule object

# Client information
request.remote_addr   # Client IP address
request.user_agent    # User agent string
request.referrer      # Referring URL

Request Data Sources

Query String

Access GET parameters:
# URL: /search?q=flask&category=web
@app.route('/search')
def search():
    query = request.args.get('q')        # 'flask'
    category = request.args.get('category')  # 'web'
    
    # Get with default
    page = request.args.get('page', 1, type=int)
    
    # Get list of values
    tags = request.args.getlist('tag')
    
    return jsonify(request.args.to_dict())

Form Data

Access POST form data:
@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']  # KeyError if missing
    password = request.form.get('password')  # None if missing
    
    # Check if key exists
    if 'remember_me' in request.form:
        # Set remember cookie
        pass
    
    return redirect('/dashboard')

JSON Data

Parse JSON request bodies:
@app.route('/api/users', methods=['POST'])
def create_user():
    # Automatically parses JSON
    data = request.get_json()
    
    # Force parsing even without Content-Type
    data = request.get_json(force=True)
    
    # Silent mode (returns None on error)
    data = request.get_json(silent=True)
    
    if data:
        name = data.get('name')
        email = data.get('email')
        return jsonify({'id': 123, 'name': name}), 201
    
    return jsonify({'error': 'Invalid JSON'}), 400

File Uploads

Handle uploaded files:
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return 'No file part', 400
    
    file = request.files['file']
    
    if file.filename == '':
        return 'No selected file', 400
    
    if file:
        filename = secure_filename(file.filename)
        file.save(f'/uploads/{filename}')
        return 'File uploaded', 201

Raw Data

Access raw request body:
@app.route('/webhook', methods=['POST'])
def webhook():
    # Raw bytes
    raw_data = request.data
    
    # As text
    text_data = request.get_data(as_text=True)
    
    # Stream for large files
    stream = request.stream
    
    return 'OK'

Request Limits

From wrappers.py:60-144, Flask provides security limits:
# Application-level defaults
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16 MB
app.config['MAX_FORM_MEMORY_SIZE'] = 500_000  # 500 KB
app.config['MAX_FORM_PARTS'] = 1_000

# Per-request override
@app.route('/upload', methods=['POST'])
def upload():
    request.max_content_length = 50 * 1024 * 1024  # 50 MB for this route
    # ... handle upload

Blueprint Context

From wrappers.py:162-195, access blueprint information:
@app.route('/admin/users')
def admin_users():
    # Current blueprint name
    blueprint = request.blueprint  # 'admin'
    
    # All blueprint names in hierarchy
    blueprints = request.blueprints  # ['admin']
    
    # Endpoint includes blueprint
    endpoint = request.endpoint  # 'admin.users'

Response Object

The Response object represents the HTTP response sent to the client.

Creating Responses

Simple Responses

from flask import Flask, Response

app = Flask(__name__)

@app.route('/')
def index():
    # String response (converted to Response)
    return 'Hello, World!'

@app.route('/json')
def json_response():
    # Dict/list (converted to JSON)
    return {'message': 'Hello', 'status': 'success'}

@app.route('/custom')
def custom():
    # Explicit Response object
    return Response('Custom response', mimetype='text/plain')

Response Tuples

Return status code and headers:
@app.route('/created')
def created():
    # (body, status)
    return 'Resource created', 201

@app.route('/with-headers')
def with_headers():
    # (body, status, headers)
    return 'OK', 200, {'X-Custom': 'value'}

@app.route('/json-created')
def json_created():
    # (body, headers) - status inferred
    return {'id': 123}, {'Location': '/api/resource/123'}

Response Properties

From wrappers.py:222-258:
@app.route('/example')
def example():
    response = Response('Hello')
    
    # Status
    response.status_code = 200
    response.status = '200 OK'
    
    # Headers
    response.headers['X-Custom'] = 'value'
    response.headers['Content-Type'] = 'application/json'
    
    # Cookies
    response.set_cookie('session', 'abc123')
    
    # MIME type
    response.mimetype = 'text/html'  # Default for Flask
    
    return response

Setting Cookies

Manage cookies in responses:
@app.route('/login', methods=['POST'])
def login():
    response = make_response(redirect('/dashboard'))
    
    # Simple cookie
    response.set_cookie('username', 'john')
    
    # With options
    response.set_cookie(
        'session_id',
        'abc123',
        max_age=3600,           # 1 hour
        secure=True,            # HTTPS only
        httponly=True,          # No JavaScript access
        samesite='Lax'          # CSRF protection
    )
    
    return response

@app.route('/logout')
def logout():
    response = make_response(redirect('/'))
    response.delete_cookie('session_id')
    return response

make_response()

Convert return values to Response objects (from app.py:1224-1273):
from flask import make_response

@app.route('/custom')
def custom():
    # String to Response
    response = make_response('Hello')
    response.headers['X-Custom'] = 'value'
    return response

@app.route('/render')
def render():
    # Template to Response
    html = render_template('page.html')
    response = make_response(html)
    response.headers['X-Page'] = 'home'
    return response

JSON Responses

Flask provides convenient JSON handling:
from flask import jsonify

@app.route('/api/user/<int:id>')
def get_user(id):
    user = {'id': id, 'name': 'John', 'email': '[email protected]'}
    
    # jsonify() sets Content-Type to application/json
    return jsonify(user)

@app.route('/api/users')
def list_users():
    users = [{'id': 1, 'name': 'John'}, {'id': 2, 'name': 'Jane'}]
    return jsonify(users)

@app.route('/api/error')
def error():
    return jsonify({'error': 'Not found'}), 404

Streaming Responses

Stream large responses:
from flask import stream_with_context

@app.route('/large-file')
def large_file():
    def generate():
        with open('large_file.txt') as f:
            for line in f:
                yield line
    
    return Response(generate(), mimetype='text/plain')

@app.route('/events')
def events():
    def generate():
        for i in range(10):
            yield f'data: {i}\n\n'
            time.sleep(1)
    
    return Response(generate(), mimetype='text/event-stream')

File Downloads

Send files to clients:
from flask import send_file, send_from_directory

@app.route('/download/<filename>')
def download(filename):
    return send_from_directory('files', filename, as_attachment=True)

@app.route('/report')
def report():
    # Send file-like object
    buffer = BytesIO()
    buffer.write(b'Report content')
    buffer.seek(0)
    
    return send_file(
        buffer,
        mimetype='application/pdf',
        as_attachment=True,
        download_name='report.pdf'
    )

Request Context

The request object is context-local, available only during request handling:
from flask import request, has_request_context

def get_user_ip():
    if has_request_context():
        return request.remote_addr
    return None

@app.route('/')
def index():
    ip = get_user_ip()  # Works here
    return f'Your IP: {ip}'

# Outside request context
ip = get_user_ip()  # Returns None

Modifying Responses

After Request Handlers

Modify all responses:
@app.after_request
def add_header(response):
    response.headers['X-Custom-Header'] = 'value'
    response.headers['Cache-Control'] = 'no-store'
    return response

Per-Request Modifications

Modify specific request responses:
from flask import after_this_request

@app.route('/special')
def special():
    @after_this_request
    def add_special_header(response):
        response.headers['X-Special'] = 'true'
        return response
    
    return 'Special page'

Best Practices

Validate Input

Always validate and sanitize request data

Set Limits

Configure MAX_CONTENT_LENGTH to prevent DOS attacks

Use get() Method

Use .get() instead of dict access to avoid KeyError

Secure Cookies

Always use secure, httponly cookies for sensitive data

Build docs developers (and LLMs) love