Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RedirectResponse from a POST request route to GET request route shows 405 Error code. #1498

Closed
aminPial opened this issue May 31, 2020 · 10 comments

Comments

@aminPial
Copy link

aminPial commented May 31, 2020

Summary of the total issue is: How to do a Post/Redirect/Get (PRG) in FastAPI?

This is not necessarily a bug, rather a question.

Things i tried:

I want to redirect response from 2nd route to 1st route. This Issue#199 here explains GET to GET but not a POST to GET. N.B: I have done this type of POST -> GET redirecting in flask, it was working there but not here. And also this Issue#863 has the same problem but doesn't really solves the problem. To re produce the error check the bottom.

#1st route (GET request)
@admin_content_edit_router.get('/admin/edit_content/set_category')
async def set_category(request:Request):
     return templates.TemplateResponse("admin/category_edit.html", {'request': request})

#2nd route (POST request)
@admin_content_edit_router.post('/admin/edit_content/add_category')
async def add_category(request:Request):
        # here forms are getting processed
        return RedirectResponse(app.url_path_for('set_category')) # from here to 1st route

But it shows :

 {"detail":"Method Not Allowed"}

Full traceback:

INFO:     127.0.0.1:58415 - "POST /admin/edit_content/add_category HTTP/1.1" 307 Temporary Redirect
INFO:     127.0.0.1:58415 - "POST /admin/edit_content/set_category HTTP/1.1" 405 Method Not Allowed
ERROR:    Exception in callback _SelectorSocketTransport._read_ready()
handle: <Handle _SelectorSocketTransport._read_ready()>
Traceback (most recent call last):
  File "c:\users\aminp\appdata\local\programs\python\python36\lib\asyncio\events.py", line 145, in _run
    self._callback(*self._args)
  File "c:\users\aminp\appdata\local\programs\python\python36\lib\asyncio\selector_events.py", line 730, in _read_ready
    self._protocol.data_received(data)
  File "c:\users\aminp\appdata\local\programs\python\python36\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 162, in data_received
    self.handle_events()
  File "c:\users\aminp\appdata\local\programs\python\python36\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 247, in handle_events
    self.transport.resume_reading()
  File "c:\users\aminp\appdata\local\programs\python\python36\lib\asyncio\selector_events.py", line 711, in resume_reading
    raise RuntimeError('Not paused')
RuntimeError: Not paused

But when i do a GET to GET redirect response it works without any issue but a POST to GET blows things up! Am i completely missing something here? i did look up in starlette doc here on reverse route lookup but nothing helps. https://www.starlette.io/routing/#reverse-url-lookups

Quick Re produce the error:

from fastapi import FastAPI
from starlette.responses import RedirectResponse
import os
from starlette.status import HTTP_302_FOUND,HTTP_303_SEE_OTHER

app = FastAPI()

@app.post("/")
async def login():
     # HTTP_302_FOUND,HTTP_303_SEE_OTHER : None is working:(
     return RedirectResponse(url="/ressource/1",status_code=HTTP_303_SEE_OTHER)

@app.get("/ressource/{r_id}")
async def get_ressource(r_id:str):
     return {"r_id": r_id}

if __name__ == '__main__':
    os.system("uvicorn tes:app --host 0.0.0.0 --port 80")
@aminPial aminPial added the bug Something isn't working label May 31, 2020
@phy25
Copy link

phy25 commented Jun 1, 2020

RedirectResponse uses 307 status by default: https://www.starlette.io/responses/#redirectresponse

The method and the body of the original request are reused to perform the redirected request. In the cases where you want the method used to be changed to GET, use 303 See Other instead. This is useful when you want to give an answer to a PUT method that is not the uploaded resources, but a confirmation message (like "You successfully uploaded XYZ").

The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made. With 302, some old clients were incorrectly changing the method to GET: the behavior with non-GET methods and 302 is then unpredictable on the Web, whereas the behavior with 307 is predictable. For GET requests, their behavior is identical.

https://developer.mozilla.org/docs/Web/HTTP/Status/307

To override the status code, pass parameter status_code=307 to RedirectResponse.

@aminPial
Copy link
Author

aminPial commented Jun 1, 2020

To override the status code, pass parameter status_code=307 to RedirectResponse.

Are you suggesting below snippet like this?:
return RedirectResponse(url="/ressource/1",status_code=HTTP_307_TEMPORARY_REDIRECT)

Well this doesn't really solve the problem, same error:
"GET / HTTP/1.1" 405 Method Not Allowed
Can you please try the Quick Re Produce code snippet and see what works for you, if you please!:)

@gmelodie
Copy link

If no one has already I'd like to give this a go :)

@tiangolo
Copy link
Owner

Thanks for the help here @phy25 and for the other @gmelodie ! 🚀

I actually can't reproduce it... 🤔

Here's a small app that seems to be working:

from fastapi import FastAPI, status
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.post("/")
async def login():
    return RedirectResponse(url="/ressource/1", status_code=status.HTTP_303_SEE_OTHER)


@app.get("/ressource/{r_id}")
async def get_ressource(r_id: str):
    return {"r_id": r_id}

When using the docs UI, open the browser developer tools, in the "Network" tab, to see the redirection underneath:

Selection_063

You can see that after the POST there's a GET for your path operation.

@aminPial
Copy link
Author

It's working. Thanks a lot.@tiangolo

@FIRDOUS-BHAT
Copy link

WOW !!! Thanks alot !!! Was facing with the same issue. Resolved Now :)

@Suman2023
Copy link

How to redirect from GET to POST i used the above there but got 405 error. please help

@mcleantom
Copy link

@Suman2023 You most likely have to enable CORS

@preetam-kotteda
Copy link

@tiangolo great solution faced the same issue and resolved, but can you please elaborate why it wasnt working without explicit status code.

@mcleantom
Copy link

@tiangolo great solution faced the same issue and resolved, but can you please elaborate why it wasnt working without explicit status code.

The RedirectResponse by default uses HTTP 307 - Temporary Redirect. The documentation for that says

307 guarantees that the method and the body will not be changed when the redirected request is made.

The browser will do all the work for you to redirect, based on the status code. 303 See Other will redirect to another URL, using a GET request. I assume it will not work for redirecting to a POST, PUT or DELETE endpoint

@tiangolo tiangolo added question Question or problem reviewed and removed bug Something isn't working labels Feb 22, 2023
@tiangolo tiangolo changed the title [BUG] RedirectResponse from a POST request route to GET request route shows 405 Error code. RedirectResponse from a POST request route to GET request route shows 405 Error code. Feb 24, 2023
@tiangolo tiangolo reopened this Feb 28, 2023
@github-actions github-actions bot removed the answered label Feb 28, 2023
Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #7451 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests

8 participants