Fastapi: [BUG] Static files broken

Created on 7 Jul 2019  路  7Comments  路  Source: tiangolo/fastapi

Describe the bug
I want to expose api endpoint from which I can download static directory. I get 2 unexpected behaviors:

  1. When I want to reach my endpoint 0.0.0.0/static I see No operations defined in spec!
  2. From tutorials(mentioned below) I understood it takes file from my app directory? Unless I copy it to root of my OS I get error raise RuntimeError(f"Directory '{directory}' does not exist").

This is really important for my home project to make sense so any input is really appreciated because I'm stuck on this.

To Reproduce
Code:

from starlette.staticfiles import StaticFiles
from fastapi import FastAPI

app = FastAPI(title="static_api")
app.mount("/static", StaticFiles(directory="static"))

Dockerfile:

FROM python:3.7
RUN pip install aiofiles fastapi uvicorn python-multipart 
EXPOSE 80
COPY ./app /app
COPY ./static /static

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]

I use docker build -t myimage . and docker run -p 80:80 myimage.

Expected behavior
Download static directory(or at least any file from this dir) from 0.0.0.0/static

Environment:
Docker above.

Already viewed and tried issues/tutorials
https://fastapi.tiangolo.com/tutorial/static-files/
https://www.starlette.io/staticfiles/
https://github.com/tiangolo/fastapi/issues/130

bug

Most helpful comment

@yaronv you might be able to pass absolute paths without needing to actually hard code an absolute path by doing something like:

from pathlib import Path

current_file = Path(__file__)
current_file_dir = current_file.parent
project_root = current_file_dir.parent
project_root_absolute = project_root.resolve()
static_root_absolute = project_root_absolute / "static"  # or wherever the static folder actually is

Obviously you can reduce the number of lines involved, I just made it more verbose to make it clear what was going on.

Or you could also use an environment variable/config as you noted.

All 7 comments

Even if this answer comes a little late, maybe it helps others, because I got into the same problem in the beginning.

I am not sure if this is a bug either?
Because it's called static file and not static directory.

So you won't be able to request a folder, only a file, which has to be explicit.

0.0.0.0/static/existing_file

if you want to get files as folder you could zip your files to one file

0.0.0.0/static/existing_files.zip

If the error result is that the folder was not found, then a wrong specification must have happened. The following should run, if you want static inside you app-folder:

from starlette.staticfiles import StaticFiles
from fastapi import FastAPI

app = FastAPI(title="static_api")
app.mount("/static", StaticFiles(directory="app/static"))

So you don't need to copy the static folder in dockerfile additionaly.

this works fine on docker but when you try to run the main.py it says the folder does not exist

Can you share the full stack trace? In particular, is the error coming from StaticFiles or somewhere downstream?

If you are just getting raise RuntimeError(f"Directory '{directory}' does not exist") then this should be easy enough to solve by just getting the directory right. You might need to use an absolute path somewhere that you are currently using a relative path, or vice versa.

I would recommend trying to run in a debugger and investigating if you can figure out where it is looking / why it can't find the directory at the point where the error is occurring. If you ultimately find an inconsistency between the runtime behavior and the FastAPI and/or starlette docs, please let us know.


Edit: I see this issue is actually rather old; I'm assuming the original issue has been addressed (there have certainly been some updates to starlette since this issue was opened that have fixed issues with serving static files).

@yaronv if you are still running into issues, the first part of the comment may still be relevant to you.

Ok, Thanks, I understand the solution above.
It's just that It's annoying to use absolute path because the path is different between the local machine and the docker environment.
Never mind, I will use some configs for that.
Thanks!

@yaronv you might be able to pass absolute paths without needing to actually hard code an absolute path by doing something like:

from pathlib import Path

current_file = Path(__file__)
current_file_dir = current_file.parent
project_root = current_file_dir.parent
project_root_absolute = project_root.resolve()
static_root_absolute = project_root_absolute / "static"  # or wherever the static folder actually is

Obviously you can reduce the number of lines involved, I just made it more verbose to make it clear what was going on.

Or you could also use an environment variable/config as you noted.

Thanks @dmontagu for the help here!

I think that should answer the question, right @MLman99 ?

Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.

Was this page helpful?
0 / 5 - 0 ratings