Based on a few FastAPI tutorials, including this, I made a simple FastAPI app:
from fastapi import FastAPI, Request
app = FastAPI() # also tried FastAPI(root_path="/api/v1")
@app.get("/app")
def read_main(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}
Which i want to have at a path other than root (e.g. /api/vi)... Again based on most tutorials and common sense, I tried to start it with e.g.:
uvicorn main:app --root-path /api/v1
The service comes up ok (on http://127.0.0.1:8000), however, the root-path seems to be ignored: Any GET request to http://127.0.0.1:8000/ gives:
message "Hello World"
root_path "/api/v1"
and any GET request to http://127.0.0.1:8000/api/v1 gives:
detail "Not Found"
I would expect the requests to produce the reverse outcomes... What is going on here?!?
I also tried initializing FastAPI with FastAPI(root_path="/api/v1") as well as switching to hypercorn without avail...
Details of the versions of apps (I might have tried a few others as well, though these should be the latest tried):
python 3.9.7 hf930737_3_cpython conda-forge
fastapi 0.85.1 pyhd8ed1ab_0 conda-forge
uvicorn 0.20.0 py39h06a4308_0
hypercorn 0.14.3 py39hf3d152e_1 conda-forge
As noted by @MatsLindh in the comments section,
root_path(or--root-path) does not change your application's prefix path, but is rather designated for behind the proxy cases, where "you might need to use a proxy server like Traefik or Nginx with a configuration that adds an extra path prefix that is not seen by your application" (see the relevant documentation).As described in the documentation:
Option 1
Hence, in your case, since you are not using a proxy, but rather need to have a custom prefix for your API, you could instead use an
APIRouter, which allows you to define aprefixfor the API routes (note that theprefixmust not include a final/). You can either give theprefixwhen instantiating theAPIRouter(e.g.,router = APIRouter(prefix='/api/v1')) or using.include_router(), which, as described in the documentation, would allow you to include the same router multiple times with different prefix:The
/appendpoint in the example below can be accessed at http://127.0.0.1:8000/api/v1/app.Working Example
Once you have multiple versions of the API endpoints, you could use:
Option 2
Alternatively, one could also mount sub-application(s) with the desired
prefix, as demonstrated in this answer and this answer (see Option 3).As described in the documentation:
Hence, in the example given below, you can access the
/appendpoint from the main app at http://127.0.0.1:8000/app and the/appendpoint from the sub app at http://127.0.0.1:8000/api/v1/app. Similarly, the Swagger UI autodocs can be accessed at http://127.0.0.1:8000/docs and http://127.0.0.1:8000/api/v1/docs, respectively.Working Example