Skip to main content

Subclassing Request and Response

To add custom helper methods to every request or ensure every response includes specific headers, you can replace the default classes used by Flask by subclassing Request and Response.

Subclassing Request

You can extend flask.Request to add application-specific properties or modify how request data is handled. For example, you might want a shortcut to check if a request is targeting an API endpoint.

from flask import Flask, Request

class CustomRequest(Request):
@property
def is_api(self):
return self.path.startswith("/api/v1/")

app = Flask(__name__)
app.request_class = CustomRequest

@app.route("/api/v1/status")
def status():
# request is an instance of CustomRequest
if request.is_api:
return {"status": "ok"}
return "OK"

Overriding Request Limits

The Request class provides properties for content length and form limits that default to the application's configuration. In Flask 3.1 and later, you can override these limits on a per-request basis within your subclass or a before_request handler.

class LargeUploadRequest(Request):
@property
def max_content_length(self):
# Dynamically increase limit for specific endpoints
if self.endpoint == "upload_large_file":
return 100 * 1024 * 1024 # 100MB
return super().max_content_length

app.request_class = LargeUploadRequest

The following properties can be customized:

  • max_content_length: Maximum size of the request body (defaults to MAX_CONTENT_LENGTH config).
  • max_form_memory_size: Maximum size of non-file form fields (defaults to MAX_FORM_MEMORY_SIZE config).
  • max_form_parts: Maximum number of form fields (defaults to MAX_FORM_PARTS config).

Subclassing Response

Subclassing flask.Response is useful for changing the default mimetype or automatically injecting headers into every response generated by the application.

from flask import Flask, Response

class CustomResponse(Response):
# Change default mimetype from text/html
default_mimetype = "application/json"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Add a custom header to every response
self.headers["X-App-Version"] = "1.0.0"

app = Flask(__name__)
app.response_class = CustomResponse

@app.route("/")
def index():
# This dict will be wrapped in CustomResponse
return {"message": "hello"}

Integration and Internal Mechanics

Flask uses the classes assigned to app.request_class and app.response_class throughout the request lifecycle:

  1. Request Creation: When a request arrives, Flask calls AppContext.from_environ, which instantiates the request_class.
  2. Response Coercion: The make_response helper (and the internal logic that handles view return values) ensures that the final response is an instance of response_class. If a view returns a string or a tuple, Flask passes those arguments to the response_class constructor.
  3. Testing: The test_client also respects these classes, ensuring that your custom properties and headers are available during unit tests.

Troubleshooting and Gotchas

  • JSON Provider: If you need to change how JSON is parsed or serialized, you should set the json_module attribute on your subclass to a custom module or object that implements dumps and loads.
  • Read-only Properties: Some properties, like Response.max_cookie_size, are read-only views of the application configuration (MAX_COOKIE_SIZE). They cannot be modified by setting the attribute on the instance; they must be changed via app.config.
  • Mimetype Defaults: Flask's Response class sets default_mimetype = "text/html". If you are building a pure API, overriding this in a subclass is more efficient than setting it manually in every view.
  • Debug Mode Behavior: In debug mode, the Request class may replace the files multi-dict with a specialized version that provides more descriptive error messages for common issues like missing enctype="multipart/form-data". Custom subclasses should call super()._load_form_data() if they override form loading logic.