Fastapi: 307 on a delete for a post request.

Created on 3 Apr 2020  路  5Comments  路  Source: tiangolo/fastapi

Describe the bug

When a delete is made on a post route with a trailing slash the server returns a 307 temporary redirect. I would either expect a 404 not found or a 405 method not allowed.

To Reproduce

Just a unittest to show the case:

from fastapi import FastAPI, Request, Response
from fastapi.testclient import TestClient

app = FastAPI()


@app.post("/bla")
async def bla():
    return {}


client = TestClient(app)


def test_read_main():
    response = client.delete("/bla/")
    print(response.headers)
    assert response.status_code == 405

Environment

  • OS: all
  • FastAPI Version: 0.53.2
  • Python Version: 3.8.2
bug

Most helpful comment

Just had a look into this. The main FastAPI instance has an APIRouter.

When you create separate fastapi.routing.APIRouter instances and then use app.include_router(...), behind the scenes it is actually appending the routes from this router to FastAPI#router.

This should work:

app = FastAPI()
app.router.redirect_slashes = False

Seems that redirect_slashes means "redirect paths without trailing slash to slash", NOT "redirect trailing slash to no slash".

_starlette/routing.py:601_

        if scope["type"] == "http" and self.redirect_slashes:
            if not scope["path"].endswith("/"):
                redirect_scope = dict(scope)
                redirect_scope["path"] += "/"

Also, if you are using a FastAPI or Flask backend via a proxy (like in CRA setupProxy.js with http-proxy-middleware), then you have some additional work to do as described here: https://github.com/chimurai/http-proxy-middleware/issues/140#issuecomment-611237707

All 5 comments

Your path has some error.
you should use :response = client.delete("/bla")

Interesting. This behavior is actually controlled by starlette.router.Router.redirect_slashes, so you might want to give it a try.

However on my end during the TestClient test that property is not kept, which might be a bug:

from fastapi import FastAPI, APIRouter
from starlette.testclient import TestClient

app = FastAPI()
router = APIRouter(redirect_slashes=False)

@router.post("/bla")
async def bla():
    return {}

app.include_router(router)

client = TestClient(app)


def test_read_main():
    assert router.redirect_slashes == False # success
    assert client.app.router.redirect_slashes == False #fail
    response = client.post("/bla/")
    print(response.headers)
    assert response.status_code >= 400

@Dustyposa I think they just want that path without slashes not getting redirected. It's intended.

Yep, this seems to be a bug but I can't figure out where it is coming from. The redirect_slashes=False is definitely being ignored on my end.

Starlette is only supposed to be redirecting slashes if redirect_slashes is True (which it is by default), but if you set it to False in a fastapi.APIRouter, FastAPI is in fact passing that kwarg down to starlette.routing.Router, which in turn appears to only redirect if that param is true.

Very strange.

Just had a look into this. The main FastAPI instance has an APIRouter.

When you create separate fastapi.routing.APIRouter instances and then use app.include_router(...), behind the scenes it is actually appending the routes from this router to FastAPI#router.

This should work:

app = FastAPI()
app.router.redirect_slashes = False

Seems that redirect_slashes means "redirect paths without trailing slash to slash", NOT "redirect trailing slash to no slash".

_starlette/routing.py:601_

        if scope["type"] == "http" and self.redirect_slashes:
            if not scope["path"].endswith("/"):
                redirect_scope = dict(scope)
                redirect_scope["path"] += "/"

Also, if you are using a FastAPI or Flask backend via a proxy (like in CRA setupProxy.js with http-proxy-middleware), then you have some additional work to do as described here: https://github.com/chimurai/http-proxy-middleware/issues/140#issuecomment-611237707

Now the question should be, what is default behavior and what is HTTP standard?
Responding with a redirect to an other verb then GET feels wired for me, but idk if this is just subjective...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

laith43d picture laith43d  路  3Comments

danielgtaylor picture danielgtaylor  路  3Comments

DrPyser picture DrPyser  路  3Comments

kkinder picture kkinder  路  3Comments

scheung38 picture scheung38  路  3Comments