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 toMAX_CONTENT_LENGTHconfig).max_form_memory_size: Maximum size of non-file form fields (defaults toMAX_FORM_MEMORY_SIZEconfig).max_form_parts: Maximum number of form fields (defaults toMAX_FORM_PARTSconfig).
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:
- Request Creation: When a request arrives, Flask calls
AppContext.from_environ, which instantiates therequest_class. - Response Coercion: The
make_responsehelper (and the internal logic that handles view return values) ensures that the final response is an instance ofresponse_class. If a view returns a string or a tuple, Flask passes those arguments to theresponse_classconstructor. - Testing: The
test_clientalso 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_moduleattribute on your subclass to a custom module or object that implementsdumpsandloads. - 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 viaapp.config. - Mimetype Defaults: Flask's
Responseclass setsdefault_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
Requestclass may replace thefilesmulti-dict with a specialized version that provides more descriptive error messages for common issues like missingenctype="multipart/form-data". Custom subclasses should callsuper()._load_form_data()if they override form loading logic.