FastAPI application as an AWS lambda function URL gets stuck in eternal redirect loop

Viewed 239

I have a FastAPI app that I use as an AWS Lambda function. It is configured so that its URL is directly callable (using the recent AWS function URL functionality).

FastAPI functions that are set directly with the app (eg @app.get("/")) work fine, but calling endpoints that are loaded in via app.include_router() are stuck in an endless 307 loop.

The app layout is (simplified):

+ app
|-- main.py
|-- routers
|---- ingest.py

main.py contents (simplified):

app = FastAPI()
app.include_router(ingest.router)

@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse("home.html", {"request": request})

@app.get("/login", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse("login.html", {"request": request})

handler = Mangum(app)

ingest.py contents (simplified):

...
router = APIRouter(prefix="/ingest")
@router.post("/")
async def ingest(meal: str):
    ...

It seems this has something to do with appending slashes, but the strange thing is that I don't get a 307 redirect when I do any of these:

GET https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/
GET https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/login  (<- missing slash)
GET https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/login/ (<- note the slash)

while the call gets stuck in a 307 redirect loop when I do any of these:

GET https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/ingest   (<- missing slash)
GET https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/ingest/  (<- note the slash)
POST https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/ingest  (<- missing slash)
POST https://xxxxxxxxxxxx.lambda-url.eu-west-1.on.aws/ingest/ (<- note the slash)

I don't have this issue locally, nor when I deploy the app to a local docker container.

What could be causing this behaviour?

1 Answers

As I finished writing this question, I stumbled on this github issue. Adding an extra decorator to the functions in ingest.py prevents the endless redirect loop:

router = APIRouter(prefix="/ingest")
@router.post("/")
@router.post("")
async def ingest(meal: str):
...

Still, I don't understand why this is an issue... (and the solution feels hacky).

Related