Root Path in Fast API behind ALB

Viewed 124

I am deploying a fast API app behind AWS ALB, with listener rule path pattern /api/v1/ points towards fast API. My app looks like this

from typing import Union
import os
import mysql.connector
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    print("Root path hit")
    return {"App": "Fargate"}


@app.get("/api/v1/")
def read_apiv1():
    print("Root path hit")
    return {"App": "Path Fargate API v1"}

I deployed the app in ECS using docker and my docker run command is

CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80", "--root-path", "/api/v1"]

Now when I hit my AWS ALB dns suffixed with /api/v1/ I see the endpoint /api/v1 which throws the response {"App": "Path Fargate API v1"}. However, based on the documentation from fast API it should load the api endpoint with /.

Can anyone help me why I am getting this unexpected behavior? Do I have to manually write /api/v1 before all of my endpoints?

2 Answers

Having a proxy with a stripped path prefix, in this case, means that you could declare a path at /app in your code, but then, you add a layer on top (the proxy) that would put your FastAPI application under a path like /api/v1.

In this case, the original path / would actually be served at /api/v1.

Even though all your code is written assuming there's just /.

And the proxy would be "stripping" the path prefix on the fly before transmitting the request to Uvicorn, keep your application convinced that it is serving at /, so that you don't have to update all your code to include the prefix /api/v1.

Reference: https://fastapi.tiangolo.com/advanced/behind-a-proxy/?h=root_#proxy-with-a-stripped-path-prefix

About root_path

Have in mind that the server (Uvicorn) won't use that root_path for anything else than passing it to the app.

But if you go with your browser to http://127.0.0.1:8000/app you will see the normal response:

{
    "message": "Hello World",
    "root_path": "/api/v1"
}

So, it won't expect to be accessed at http://127.0.0.1:8000/api/v1/app.

Uvicorn will expect the proxy to access Uvicorn at http://127.0.0.1:8000/app, and then it would be the proxy's responsibility to add the extra /api/v1 prefix on top.

This is how I added /api/v1 to all my routes:

from sys import prefix
from typing import Union
import os
from fastapi import FastAPI, APIRouter

app = FastAPI()

prefix_router = APIRouter(prefix="/api/v1")

@prefix_router.get("/")
def read_root():
    print("Root path hit")
    return {"App": "Fargate"}


@prefix_router.get("/something/")
def read_apiv1():
    print("Root path hit")
    return {"App": "Path Fargate API v1"}

app.include_router(prefix_router)

After this when I go to http://127.0.0.1/api/v1/something/ path it automatically redirects me to the second route.

Related