starlette.routing.NoMatchFound when including Starlette router into FastAPI app
See original GitHub issueDescribe the bug
I have an FastAPI app object which I want to use to several applications via including them as a routers:
import uvicorn
from fastapi import FastAPI
from api import vlantoggler_api_router
from views import vlantoggler_web_router
app = FastAPI()
app.include_router(vlantoggler_api_router,
prefix='/vlantoggler/api')
app.include_router(vlantoggler_web_router,
prefix='/vlantoggler')
if __name__ == "__main__":
uvicorn.run(app, loop='uvloop', log_level='debug')
Then here is my api_router:
vlantoggler_api_router = APIRouter(
# title='Yandex.Cloud Netinfra API',
# description='A bundled API for Yandex.Cloud Netinfra team tools',
routes=[
APIRoute('/', check, methods=['GET'], tags=['VlanToggler'],
name='Get current interface state',
# summary='String replaces function name AND name on Swagger API page',
description='ToR and Interface names are validated and current interface state is returned',
response_description='Successfully got interface state',
response_class=JSONResponse,
response_model=Success,
responses={**get_responses}
),
APIRoute('/', toggle, methods=['POST'], tags=['VlanToggler'],
name='Switch interface state',
description='ToR and Interface names are validated and ToR interface is toggled to desired state',
response_description='Interface successfully switched',
response_class=JSONResponse,
response_model=Success,
responses={**post_responses},
),
],
)
and web form router
vlantoggler_web_router = Router(
[
Route('/', home, methods=['GET', 'POST']),
Mount('/statics', statics, name='static'),
],
)
As you can see I just import them from another module to make things nice and clean.
To Reproduce
When I run the app:
python3 ft.py
INFO: Started server process [14057]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
My api works perfectly fine and accessable via http://127.0.0.1:8000/vlantoggler/api/
.
There is also nothing wrong with the /docs
, they are at http://127.0.0.1:8000/docs
as I want it.
BUT web form doesn’t work (should be accessable via http://127.0.0.1:8000/vlantoggler/
). I have an Internal Server Error instead:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/usr/local/lib/python3.6/dist-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "/usr/local/lib/python3.6/dist-packages/fastapi/applications.py", line 151, in __call__
await super().__call__(scope, receive, send) # pragma: no cover
File "/usr/local/lib/python3.6/dist-packages/starlette/applications.py", line 102, in __call__
await self.middleware_stack(scope, receive, send)
File "/usr/local/lib/python3.6/dist-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "/usr/local/lib/python3.6/dist-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/usr/local/lib/python3.6/dist-packages/starlette/exceptions.py", line 82, in __call__
raise exc from None
File "/usr/local/lib/python3.6/dist-packages/starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "/usr/local/lib/python3.6/dist-packages/starlette/routing.py", line 550, in __call__
await route.handle(scope, receive, send)
File "/usr/local/lib/python3.6/dist-packages/starlette/routing.py", line 227, in handle
await self.app(scope, receive, send)
File "/usr/local/lib/python3.6/dist-packages/starlette/routing.py", line 41, in app
response = await func(request)
File "/home/horseinthesky/vl_proto/views.py", line 83, in home
return render(request)
File "/home/horseinthesky/vl_proto/views.py", line 40, in render
return templates.TemplateResponse('index.html', context)
File "/usr/local/lib/python3.6/dist-packages/starlette/templating.py", line 87, in TemplateResponse
background=background,
File "/usr/local/lib/python3.6/dist-packages/starlette/templating.py", line 27, in __init__
content = template.render(context)
File "/usr/local/lib/python3.6/dist-packages/jinja2/asyncsupport.py", line 76, in render
return original_render(self, *args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/usr/local/lib/python3.6/dist-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.6/dist-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "templates/index.html", line 10, in top-level template code
<link href="{{ url_for('static', path='/css/bootstrap.min.css') }}" rel="stylesheet">
File "/usr/local/lib/python3.6/dist-packages/starlette/templating.py", line 59, in url_for
return request.url_for(name, **path_params)
File "/usr/local/lib/python3.6/dist-packages/starlette/requests.py", line 137, in url_for
url_path = router.url_path_for(name, **path_params)
File "/usr/local/lib/python3.6/dist-packages/starlette/routing.py", line 486, in url_path_for
raise NoMatchFound()
starlette.routing.NoMatchFound
Expected behavior
Web router should be working on http://127.0.0.1:8000/vlantoggler/
Environment
- OS: Ubuntu 18.04.03
- FastAPI Version
0.52.0
, get it with:pip
- Starlette Version 0.13.2, get it with
pip
python3 -c "import fastapi; print(fastapi.__version__)"
0.52.0
- Python version 3.6.7, get it with System
python3 --version
Python 3.6.7
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (2 by maintainers)
Top Results From Across the Web
starlette.routing.NoMatchFound: No route exists for name ...
As you know this error is output by class Router in routing.py I am developing a service with FastAPI as just REST API...
Read more >Routing - Starlette
Starlette has a simple but capable request routing system. A routing table is defined as a list of routes, and passed when instantiating...
Read more >tiangolo/fastapi - Gitter
and in my tests url = app.url_path_for("users_byemail") fails. with starlette.routing.NoMatchFound. I can see users_byemail in [r.name for r in app.routes].
Read more >Static Files - FastAPI
FastAPI provides the same starlette.staticfiles as fastapi.staticfiles just ... The OpenAPI and docs from your main application won't include anything from ...
Read more >starlette.routing.Router Example - Program Talk
Router. Learn how to use python api starlette.routing.Router. ... on this Operation" # error triggered with lifespan with TestClient(app) as client: with ......
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@horseinthesky & @tiangolo Thanks for getting to the bottom of this one. The switch from APIRouter to a mounted sub-application (class FastAPI) with mounted static directory worked, it allowed me to directly access the file via the expected URL.
I just wanted to mention that my
url_for()
calls in my template needed to have their name parameter prefixed with the sub-application name and a colon. This is because I had set the name field when I mounted my sub-application.For Example: Using your code from above, if you had mounted your sub-application with a name parameter like the following
You would have also needed to change your
url_for
calls in templates fromto
This tripped me up for awhile but just wanted to make a note of it for anyone else having this issue. Had to hunt through the code to find what I was doing wrong. Only found a small mention of it after the fact in the Starlette 0.7.1 release notes, might be worth noting in the Sub-Application or Templates & Static-Files docs.
Anyways thanks for all the hard work, You guys rock! 🎉🎉🎉
@tiangolo Thank you very much. I changed
to
And then included
APIRouters
withinclude_router
andAnd this worked perfectly fine.
Just want to clarify:
Router
fromstarlette.routing
is not similar object toAPIRouter
fromfastapi.routing
? And I cannotinclude_router
aRouter
object toFASTApi
app object?!So
Router
is more like anotherFASTApi
object and I can only mount one to another?