-
-
Notifications
You must be signed in to change notification settings - Fork 990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make router and route classes configurable via subclassing #2904
base: master
Are you sure you want to change the base?
Conversation
- Allow `Starlette` to specify a custom router by overriding `router_class`. - Allow `Router` to specify custom route classes by overriding `route_class` and `websocket_route_class`. - Improve extensibility for custom implementations. - Minor typo fix in Starlette class docstring. - Update .gitignore to exclude IDE (.idea) and virtual environment directories (.venv).
If I understand correctly the point is to make
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Mount, Route, Router
from starlette.testclient import TestClient
async def homepage(_request: Request) -> JSONResponse:
return JSONResponse({'message': 'Hello, world!'})
router = Router(routes=[Route('/home', endpoint=homepage)])
app = Starlette(routes=[Mount('', app=router)])
client = TestClient(app)
resp = client.get('/home')
assert resp.status_code == 200
print(resp.json()) # Prints: {'message': 'Hello, world!'} Given that this isn't a supper common use case and it's targeted at deprecated APIs I don't think we'd want to add it. The only argument I see for something like this is that as far as I can tell you can't set the router class on the Starlette object. If we wanted to be able to allow that (and I'm not sure we do, I don't know what the use case would be) I think that should be done by adding a |
@adriangb Thanks for the detailed feedback! The intention behind my PR wasn’t just to customize router usage via decorators (like @app.get) but rather to allow setting a custom router class directly during Starlette initialization, since currently Starlette always initializes its internal router as the default one, even if we pass custom routes or routers. While your suggestion using Mount works, the core limitation remains: Starlette always internally creates its default router instance at init. This makes it difficult to customize routing behaviour deeply globally (e.g., extending routing functionality, creating Flask Blueprint-like modular/sub-router structures). My main motivation is to have router modularity, somewhat similar to Flask’s Blueprint feature, but with deeper nesting capabilities. For example, I’d like to structure my routers like:
Currently, using Mount means each sub-router is essentially treated as a separate application, which slightly complicates handling middleware, error handling, or extensions across sub-router boundaries. Therefore, adding a router parameter to the Starlette constructor (as you suggested, mutually exclusive with routes) would elegantly solve this issue and provide deeper control over router behavior without relying on deprecated decorators. Would you be open to reconsidering if I adjusted my PR to implement exactly that—a way to directly inject a custom router into Starlette via the constructor? |
I'm still not sure I completely understand the use case but I do think it'd be reasonable to add a |
I think this PR came out a couple of times in the last 5 years, or maybe it was discussed... can we get the reference to those? I'd like to see the concerns we had at the time. |
Summary
This PR allows customization of the router and route classes used by Starlette. It introduces flexibility by enabling users to subclass
Starlette
andRouter
to specify custom implementations, enhancing the extensibility of the framework.Key Changes:
router_class
attribute in theStarlette
class to enable specifying custom routers via subclassing.route_class
andwebsocket_route_class
attributes to theRouter
class to allow overriding the default route implementations..gitignore
to ignore IDE-specific files (.idea
) and local virtual environment directories (.venv
).Starlette
class docstring.This approach maintains backward compatibility while significantly improving flexibility for developers building on top of Starlette.
Checklist
Motivation
We needed this flexibility to integrate Starlette with custom routing logic tailored for specific performance or organizational requirements, without modifying core library code directly.