question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Including router which has a Mount on "/" does not work

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from fastapi.applications import FastAPI
from fastapi.responses import FileResponse
from fastapi.routing import APIRouter
from starlette.routing import Route

frontend_router = APIRouter()


async def index_fallback(request):
    return FileResponse("static/index.html")


frontend_router.mount("/", Route("/", index_fallback))

app = FastAPI()
app.include_router(frontend_router)

Description

I expect being able to include a router which has applications mounted at the root.

The problem seems to be that starlette strips any leading slashes from Mounts such that the resulting path is "". For starlette itself this is no problem and it can handle those fine. When calling include_router on a FastAPI instance it is however checked that either the prefix starts with (1a) and does not end with (1b) a slash or that every route has a non-empty path (2). The mount with an empty path is in violation of 2. Passing a prefix would solve this issue in most cases however when the router should not have a prefix this is not possible as a prefix of / would violate 1b.

https://github.com/tiangolo/fastapi/blob/f0388915a8b1cd9f3ae2259bace234ac6249c51a/fastapi/routing.py#L645-L657

Operating System

Linux

Operating System Details

Output of uname -a

Linux thinkpad-e570 5.15.13-200.fc35.x86_64 #1 SMP Wed Jan 5 16:39:13 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

FastAPI Version

0.72.0

Python Version

Python 3.10.1

Additional Context

The minimal example is obviously not close to real world usage. My concrete use case is that I would like to mount StaticFiles to a router which has a few other routes to override some special paths.

Minimized variant of my use case
from fastapi.applications import FastAPI
from fastapi.responses import FileResponse, PlainTextResponse
from fastapi.routing import APIRouter
from fastapi.staticfiles import StaticFiles
from starlette.routing import Route

api_router = APIRouter()


@api_router.get("/users/{username}")
async def user(username: str):
    return PlainTextResponse(f"Hello '{username}'")


frontend_router = APIRouter()


async def index_fallback(request):
    return FileResponse("static/index.html")

# one example for a path which should not be served by StaticFiles
# in this case html=True could be passed to StaticFiles but in our case there are other paths
# for which this would not work
frontend_router.mount("/", Route("/", index_fallback))
frontend_router.mount("/", StaticFiles(directory="static"), name="static")

app = FastAPI()
app.include_router(api_router, prefix="/api")
app.include_router(frontend_router)

Mounting the StaticFiles instance to the app works around this issue though it is not an optimal solution.

Furthermore it is possible to archive the same result in starlette without any problems or workarounds.

Starlette implementation of the above
from starlette.applications import Starlette
from starlette.responses import FileResponse, PlainTextResponse
from starlette.routing import Mount, Route, Router
from starlette.staticfiles import StaticFiles


async def user(request):
    return PlainTextResponse(f"Hello '{request.path_params['username']}'")


api_router = Router(
    routes=[
        Route("/users/{username}", user),
    ]
)


async def index_fallback(request):
    return FileResponse("static/index.html")


frontend_router = Router( # this works without any problems
    routes=[
        Route("/", index_fallback),
        Mount("/", StaticFiles(directory="static"), name="static"),
    ]
)

app = Starlette( # this also works without any problems
    routes=[
        Mount("/api", api_router),
        Mount("/", frontend_router),
    ]
)

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
BilalAlpaslancommented, Sep 9, 2022

use add_api_route instead of mount like frontend_router.add_api_route('/', index_fallback) because add_api_route create Route object internally and mount method not overrided by fastAPI its come from starlette

0reactions
tobiasfeilcommented, Dec 16, 2022

@BilalAlpaslan mounting an ASGI app on root works for me - at least the functional part of the API. In the Swagger UI docs however, I can’t see the operations of the subapplication when mounting on root.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Express router not mounting - Stack Overflow
I am doing my 1st project using expressjs and I am having a problem with a router not mounting. I basically have app...
Read more >
What to do if the router does not recognise the connected USB ...
Then reconnect the drive to the router. Sometimes, in the system log of the router (on the page 'Diagnostics' -> 'Show log'), you...
Read more >
I cannot mount shared folders via NFS. What should I do?
If the shared folder is successfully mounted via NFS, this means that the devices (e.g., router, switch, etc.) might have some issues.
Read more >
Your Router Is in the Wrong Spot. Here's Where To ... - CNET
Command hooks used as a router wall mount ... We'll send you the fastest internet options, so you don't have to find ......
Read more >
Key Light – Not found by Control Center - Elgato
Each router has a different way it can be reset. There may be a button on the router, or a local web page...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found