FastAPI
Setting up a FastAPI Live App on MINEO is an efficient way to deploy highly performant web applications. Follow the steps below to create your own FastAPI Live App:
Step 1: Create the main.py File
Create a file named main.py in your project directory. Keep in mind that paths in the entrypoint command are relative to the Live App's folder. This file will contain your FastAPI application code. Here's a straightforward example:
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
class ProxyPrefix:
"""Put back the path prefix MINEO's proxy strips, so `--root-path` lines up with it."""
def __init__(self, app, prefix):
self.app, self.prefix = app, prefix.rstrip("/")
async def __call__(self, scope, receive, send):
if scope["type"] in ("http", "websocket") and self.prefix and not scope["path"].startswith(self.prefix):
scope = dict(scope, path=self.prefix + scope["path"])
await self.app(scope, receive, send)
app = FastAPI()
items = [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}]
class Item(BaseModel):
id: int
name: str
@app.get("/", tags=["Default"])
def read_root():
return {"message": f"Welcome to my FastAPI application"}
@app.get("/items", response_model=List[Item], tags=["Items"])
def get_items():
return items
@app.get("/items/{item_id}", response_model=Item, tags=["Items"])
def get_item(item_id: int):
for item in items:
if item["id"] == item_id:
return item
raise HTTPException(status_code=404, detail="Item not found")
@app.post("/items", response_model=Item, tags=["Items"], status_code=201)
def create_item(item: Item):
if any(existing_item["id"] == item.id for existing_item in items):
raise HTTPException(
status_code=400, detail="Item with this ID already exists"
)
items.append(item.dict())
return item
@app.delete("/items/{item_id}", status_code=204, tags=["Items"])
def delete_item(item_id: int):
for item in items:
if item["id"] == item_id:
items.remove(item)
return
raise HTTPException(status_code=404, detail="Item not found")
# Keep this last: `uvicorn main:app` must point at the wrapper, not at the bare FastAPI instance.
app = ProxyPrefix(app, os.environ.get("MINEO_LIVE_APP_URL_PATH", ""))
This example sets up a basic FastAPI app with a root endpoint that returns a simple message.
The ProxyPrefix wrapper is what makes mounted static files, redirects, and /docs work behind MINEO's proxy. Write your routes exactly as you would locally — see Static files and the path prefix for what it does and why it is needed.
Step 2: Set Up a New Live App
Next, you need to configure a new Live App on MINEO and define an entrypoint command to run your application.
Here's the entrypoint command structure:
pip install fastapi uvicorn && uvicorn main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*' --root-path "${MINEO_LIVE_APP_URL_PATH%/}"
Adding Dependencies
If your application requires additional packages, use one of these methods to include them:
- Direct
pip install: Add necessary packages directly into the entrypoint command.
pip install fastapi uvicorn pydantic && uvicorn main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*' --root-path "${MINEO_LIVE_APP_URL_PATH%/}"
- Using
requirements.txt: List your dependencies in arequirements.txtfile and reference it in the entrypoint command.
pip install -r requirements.txt --no-cache-dir && uvicorn main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*' --root-path "${MINEO_LIVE_APP_URL_PATH%/}"
Example requirements.txt:
fastapi
uvicorn
pydantic
Configuration Needed to Share Your App
Important Launch Settings
MINEO serves every Live App behind a reverse proxy at the path stored in MINEO_LIVE_APP_URL_PATH (for example /live-app/your-org/your-app/). The proxy strips that prefix before the request reaches your app, so configure these uvicorn flags in the entrypoint to keep routing, HTTPS redirects, and /docs working:
| Flag | Why it matters |
|---|---|
--host 0.0.0.0 | Accept external connections. |
--port 8000 | The port MINEO routes to. |
--proxy-headers --forwarded-allow-ips='*' | Trust the proxy so redirects and absolute URLs use https instead of http. |
--root-path "${MINEO_LIVE_APP_URL_PATH%/}" | Tells the app the public prefix, so /docs, openapi.json and url_for() generate URLs that include it. ${...%/} strips the trailing slash, which --root-path must not have. |
Static files and the path prefix
--root-path alone is not enough once your app mounts anything. Add the mount to main.py above the ProxyPrefix line, while app is still the FastAPI instance:
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/assets", StaticFiles(directory="assets"), name="assets")
# ... your routes ...
app = ProxyPrefix(app, os.environ.get("MINEO_LIVE_APP_URL_PATH", ""))
Without that wrapper, the mount answers 404 to every request while your regular routes keep working — a confusing failure that looks like a missing file.
| Setup | app.mount(...) | @app.get(...) | /docs | Redirects |
|---|---|---|---|---|
No --root-path | works | works | broken | broken |
--root-path alone | 404 | works | works | broken |
--root-path + ProxyPrefix | works | works | works | works |
Why
Starlette tells a mounted sub-application how much of the path it already consumed by appending it to root_path, and the sub-application recovers its own sub-path by stripping root_path off the front. That strip only happens when the path actually starts with root_path. MINEO's proxy has already removed the prefix, so it does not, the strip silently does nothing, and StaticFiles ends up looking for assets/logo.png inside your assets directory.
Restoring the prefix before the request reaches FastAPI is what ProxyPrefix does, and it fixes redirects and /docs at the same time.
- Do not pass
root_path=to theFastAPI()constructor. It overwrites whatever--root-pathset, so a wrong value there silently beats the correct one from your entrypoint. Set the prefix in the entrypoint only. root_pathnever changes how incoming paths are matched. A404on a request that reaches your app is never fixed by changingroot_path. Look at your routes and mounts instead.MINEO_LIVE_APP_URL_PATHends with a slash androot_pathmust not, which is why the entrypoint uses${...%/}and the wrapper calls.rstrip("/").
Troubleshooting
| Symptom | Cause |
|---|---|
Images and CSS return 404, the API works | A mount() without the ProxyPrefix wrapper. |
/docs loads but stays empty | Swagger is requesting /openapi.json at the site root. Add --root-path to the entrypoint. |
| A redirect drops the prefix and lands on a MINEO error page | Missing ProxyPrefix. FastAPI builds redirects from the stripped path. |
Assets 404 and the failing URL has no /live-app/… prefix | The HTML links them with absolute paths (/assets/…), so the browser never sends the prefix. Use relative paths, or prepend MINEO_LIVE_APP_URL_PATH. |
Launch and Share Your Live App
Once your main.py and entrypoint command are set up, click the Execute button. This will deploy your FastAPI application, making it accessible.
Share your Live App URL and develop in a reliable and secure environment on the MINEO platform. Enjoy your FastAPI Live App!