He encontrado un comportamiento de redireccionamiento extraño después de devolver un objeto RedirectResponse
eventos.py
router = APIRouter() @router.post('/create', response_model=EventBase) async def event_create( request: Request, user_id: str = Depends(get_current_user), service: EventsService = Depends(), form: EventForm = Depends(EventForm.as_form) ): event = await service.post( ... ) redirect_url = request.url_for('get_event', **{'pk': event['id']}) return RedirectResponse(redirect_url) @router.get('/{pk}', response_model=EventSingle) async def get_event( request: Request, pk: int, service: EventsService = Depends() ): ....some logic.... return templates.TemplateResponse( 'event.html', context= { ... } )enrutadores.py
api_router = APIRouter() ... api_router.include_router(events.router, prefix="/event")este código devuelve el resultado
127.0.0.1:37772 - "POST /event/22 HTTP/1.1" 405 Method Not AllowedBien, veo que, por alguna razón, se llama a una solicitud POST en lugar de una solicitud GET. Busco una explicación y encuentro que el objeto RedirectResponse tiene como valor predeterminado el código 307 y llama al enlace POST
Sigo los consejos y agrego un estado.
redirect_url = request.url_for('get_event', **{'pk': event['id']}, status_code=status.HTTP_302_FOUND)Y obten
starlette.routing.NoMatchFound para el experimento, estoy cambiando @router.get('/{pk}', response_model=EventSingle) a @router.post('/{pk}', response_model=EventSingle)
y la redirección se completa con éxito, pero la solicitud de publicación no me conviene aquí. ¿Qué estoy haciendo mal?
UPD
formulario html para ejecutar eventos/crear lógica
base.html
<form action="{{ url_for('event_create')}}" method="POST"> ... </form>vista_base.py
@router.get('/', response_class=HTMLResponse) async def main_page(request: Request, activity_service: ActivityService = Depends()): activity = await activity_service.get() return templates.TemplateResponse('base.html', context={'request': request, 'activities': activity})Cuando desee redirigir a un GET después de un POST, la mejor práctica es redirigir con un código de estado 303 , así que simplemente actualice su código a:
# ... return RedirectResponse(redirect_url, status_code=303) Como habrás notado, la redirección con 307 mantiene el método y el cuerpo HTTP .
from fastapi import FastAPI, APIRouter, Request from fastapi.responses import RedirectResponse, HTMLResponse router = APIRouter() @router.get('/form') def form(): return HTMLResponse(""" <html> <form action="/event/create" method="POST"> <button>Send request</button> </form> </html> """) @router.post('/create') async def event_create( request: Request ): event = {"id": 123} redirect_url = request.url_for('get_event', **{'pk': event['id']}) return RedirectResponse(redirect_url, status_code=303) @router.get('/{pk}') async def get_event( request: Request, pk: int, ): return f'<html>oi pk={pk}</html>' app = FastAPI(title='Test API') app.include_router(router, prefix="/event") Para ejecutar, instale pip install fastapi uvicorn y ejecute con:
uvicorn --reload --host 0.0.0.0 --port 3000 example:appLuego, dirija su navegador a: http://localhost:3000/event/form
El error que menciona aquí se devuelve cuando intenta acceder al punto final event_create a través de http://127.0.0.1:8000/event/create , por ejemplo. Sin embargo, dado que la ruta event_create maneja las solicitudes POST , su solicitud termina en el punto final get_event (y devuelve un value is not a valid integer , ya que está pasando una cadena en lugar de un número entero), como cuando escribe una URL en la barra de direcciones de su navegador, realiza una solicitud GET . Por lo tanto, necesita un formulario, por ejemplo, para enviar una solicitud POST al punto final event_create . A continuación se muestra un ejemplo, similar al proporcionado por @Elias Dorneles, que puede ejecutar, por ejemplo en el puerto 8000, y acceder al formulario en http://127.0.0.1:8000/event/ para enviar una solicitud POST, que luego conducirá a RedirectResponse . Como @tiangolo publicó aquí , al realizar una RedirectResponse desde una ruta de solicitud POST a una ruta de solicitud GET, el código de estado de respuesta debe cambiar a status_code=status.HTTP_303_SEE_OTHER .
from fastapi import APIRouter, FastAPI, Request, status from fastapi.responses import RedirectResponse, HTMLResponse router = APIRouter() # Endpoint can be accessed at http://127.0.0.1:8000/event/ @router.get('/', response_class=HTMLResponse) async def event_create_form(request: Request): html_content = """ <html> <body> <h1>Create an event</h1> <form method="POST" action="/event/create"> <input type="submit" value="Create Event"> </form> </body> </html> """ return HTMLResponse(content=html_content, status_code=200) @router.post('/create') async def event_create(request: Request): event = {"id": 1} redirect_url = request.url_for('get_event', **{'pk': event['id']}) return RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER) @router.get('/{pk}') async def get_event(request: Request, pk: int): return {"pk": pk} app = FastAPI() app.include_router(router, prefix="/event")