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.
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
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...
Most helpful comment
Just had a look into this. The main
FastAPIinstance has anAPIRouter.When you create separate
fastapi.routing.APIRouterinstances and then useapp.include_router(...), behind the scenes it is actually appending the routes from this router toFastAPI#router.This should work:
Seems that
redirect_slashesmeans "redirect paths without trailing slash to slash", NOT "redirect trailing slash to no slash"._starlette/routing.py:601_
Also, if you are using a FastAPI or Flask backend via a proxy (like in CRA
setupProxy.jswithhttp-proxy-middleware), then you have some additional work to do as described here: https://github.com/chimurai/http-proxy-middleware/issues/140#issuecomment-611237707