9

I'm trying to have FastAPI work with Svelte. I've built the static files with Svelte and now I'm trying to serve them from FastAPI. The problem is that the built Svelte files reference e.g. global.css from root, which means I can't have them mounted on a subfolder.

Instead, I have to mount them on root:

app.mount("/", StaticFiles(directory="web/public", html=True), name="web")

However, this makes anything defined in routes (function decorators) inaccessible.

Is it possible have either both static files and functions defined? Either,

a) routes take precedence and if there's no route, it tries to read from static directories

b) static directories take precedence, and I specify an exclude path, which goes to routes instead

shadesofdarkred
  • 313
  • 3
  • 15
  • Which built files reference `/global.css`? Usually the location of assets (global.css or bundle.js) is defined in a .html file – joshnuss Dec 26 '20 at 10:38
  • Take a look at sapper, it uses sirv for static files and then the sapper middleware for route handling : https://github.com/sveltejs/sapper-template/blob/master/src/server.js – Romain Durand Dec 27 '20 at 04:03
  • I actually resorted to using Flask - this functionality works there. – shadesofdarkred Jan 02 '21 at 08:24

3 Answers3

12

Create an outer (root) FastAPI app and mount the StaticFiles app and your existing FastAPI app inside of it.

# Your main app must be first!
app = FastAPI(title="my app root")

api_app = FastAPI(title="my existing api")
api_app.include_router(my_existing_router)
app.mount('/api', api_app)

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

The order of mounting of the app objects seems to matter. For the OpenAPI docs, you'll have a /docs for the root app, and a /api/docs for your API app.

Hackmodford
  • 3,901
  • 4
  • 35
  • 78
ldrg
  • 4,150
  • 4
  • 43
  • 52
8

I think there's an even easier solution than those posted here: Simply mount your static folder after the definition of your other endpoints.

app = FastAPI()

@app.get("/api/hello")
async def hello():
    return "hello from fastapi"

app.mount("/", StaticFiles(directory="build", html=True), name="frontend")

You can now access the website served as a static site on root while also accessing the endpoints you might want to use for backend functionality.

pietz
  • 2,093
  • 1
  • 21
  • 23
0

You can also do this without creating an "outer (root) app"; as long as you mount the static files after you include your routers.

assuming you have:

  • fastAPI app in "project/main.py"
  • svelte stuff in "project/client"
  • "a_router" in a file "project/subfolder/do_stuff.py"

main.py

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.responses import RedirectResponse

from subfolder.do_stuff import a_router 

app = FastAPI()
app.include_router(a_router)

app.mount("", StaticFiles(directory="client/public", html=True), name="client")
app.mount("/build", StaticFiles(directory="client/public/build"), name="build")

@app.get('/')
async def client():  return RedirectResponse(url="client")