Routing not working properly with multiple Host() and Mount() objects #2243
Replies: 3 comments
-
Please let me know if this is user error, but I have tested this multiple times now and cannot see why it shouldn't be working. Edit: The reason I want to be able to register multiple Host() objects for the same subdomain is because I register my routes in sections (or blocks...) with custom route registration like this: RouteGroup(
domain="api.domain.com",
middleware=["auth"],
name="Rules",
prefix="/api",
routes=[
GET("/rules", RuleController.rules_all).name("all_rules"),
POST("/rule", RuleController.rule_new).name("new_rule"),
]
),
RouteGroup(
domain="api.domain.com",
middleware=["auth"],
name="Tasks",
prefix="/api",
routes=[
GET("/tasks", TaskController.all).name("all_tasks"),
POST("/task", TaskController.new).name("new_task"),
]
), Now that I have found the problem I could iterate over all added routes and inject routes into the same Host() object to solve the problem. I suppose this is a case of: it is not a bug, it is a feature - However it would be amazing to have support for this (Multiple Host() objects with the same domain) in Starlette by default as it already exists in other frameworks such as Sanic - see example below where you have 2 separate Blueprint objects (almost equivalent to Host() objects in Starlette) with the same domain specified: # pip install sanic
from sanic import Sanic
from sanic import Blueprint
from sanic import response
from sanic.request import Request
from sanic.response import text as PlainTextResponse
async def home(request: Request):
return PlainTextResponse("home\n")
async def foo(request: Request):
return PlainTextResponse("foo\n")
async def bar(request: Request):
return PlainTextResponse("bar\n")
foo_routes = Blueprint("Foo_Routes", url_prefix="/foo", host="api.example.com:8000")
foo_routes.add_route(foo, "/foo") # 200 OK
bar_routes = Blueprint("Bar_Routes", url_prefix="/bar", host="api.example.com:8000")
bar_routes.add_route(bar, "/bar") # 200 OK
ROUTES = [
foo_routes,
bar_routes
]
app = Sanic("test")
app.blueprint(ROUTES)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True) |
Beta Was this translation helpful? Give feedback.
-
Opened related issue: #2248 |
Beta Was this translation helpful? Give feedback.
-
Closing the discussion as @aminalaee has solved this in PR: #2263 Hopefully merged soon. |
Beta Was this translation helpful? Give feedback.
-
Hi.
I am currently using
starlette==0.31.0
and I recently encountered a weird bug where my routing broke which I couldn't figure out why at first. I decided to strip down my code to only the problematic parts in an attempt to identify the cause.It turns out there is a problem with the routing in Starlette when you use multiple Host() and Mount() objects although this should work fine according to the docs. as described here: https://www.starlette.io/routing/#submounting-routes
Routing of the first Host() or Mount works perfectly fine, but if you add a second instance to your list of routes, only the first one works. I tried to remove the Host() objects, but the same thing happens if you have two Mount() objects.
After updating your hosts file with
127.0.0.1 api.example.com
, the problem can be demonstrated by running the piece of code below, and accessing the following endpoints:http://api.example.com:8000/
-> 200 OKhttp://api.example.com:8000/foo/foo
-> 200 OKhttp://api.example.com:8000/bar/bar
-> 404 Not FoundAdditionally,
OpenAPIResponse
seems to be returning yaml instead of JSON, which makes Redoc break in the latest version of Starlette. This can be replaced withJSONResponse(schema.get_schema(routes=request.app.routes))
for intended functionality.Beta Was this translation helpful? Give feedback.
All reactions