pythonfastapisymlinkstatic-filesstarlette

FastAPI serving static files through symlinks


I have mounted the static directory in my FastAPI app using the following code:

from fastapi.staticfiles import StaticFiles

app = FastAPI(
    title="Title of the Application",
    description="Over all description of the application")
app.mount("/public", StaticFiles(directory='public'), name='public')

If I have a symlink pointing to a path outside the app folder, e.g.

/home/xyz/app/main.py
/home/xyz/app/index.html
/home/xyz/app/public/data -> /home/xyz/static/whatever.tgz

The FastAPI application can recognize the URL xyz.com/public/index.html, but it can't recognize xyz.com/public/data.

Is this doable? Unfortunately, I cannot use FileResponse due to the blob size being too large. I want to return the file with a simple link somehow.


Solution

  • Update

    Starlette has recently added the follow_symlink parameter in StaticFiles class, which is a boolean indicating if symbolic links for files and directories should be followed—by default, this value is set to False. One could set this to True, and hence, every symbolic link in the directory path should be followed. Example:

    app.mount("/static", StaticFiles(directory="static", follow_symlink=True), name="static")
    

    Given that there is a symlink called data in your static directory, you could then access, for instance, http://localhost:8000/static/data/image.png directly from your browser, or in your Jinja2 template, you could request files as follows:

    <img src="{{ url_for('static', path='data/image.png')}}" width="50%">
    

    Original Answer

    It is doable, as long as you mount a StaticFiles instance on that specific path as well. For example:

    app.mount("/static", StaticFiles(directory="static"), name="static")
    app.mount("/symlink", StaticFiles(directory="static/data"), name="publicsym")
    

    Then, in your Jinja2 template you could request files as follows:

    <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
    <img src="{{ url_for('symlink', path='/image.png')}}" width="50%">
    

    or, if there is an images sub-directory inside data:

    <img src="{{ url_for('symlink', path='images/image.png')}}" width="50%">