How can I redirect to another page/endpoint after, for instance, authenticating a user?
In flask, we can use 'request' function to redirect to a another page/endpoint, but I don't see how to do it with FastAPI.
from flask import Flask,redirect
app = Flask(__name__)
@app.route('/')
def hello():
return redirect("http://www.example.com")
Fastapi being based on Starlette you can use anything it proposes, in
particular I'd guess:
https://github.com/encode/starlette/blob/master/docs/responses.md#redirectresponse
Le ven. 3 mai 2019 Ã 5:03 PM, Marcos Monteiro notifications@github.com a
écrit :
How can I redirect to another page/endpoint after, for instance,
authenticating a user?In flask, we can use 'request' function to redirect to a another
page/endpoint, but I don't see how to do it with FastAPI.from flask import Flask,redirect
app = Flask(__name__)
@app.route('/')
def hello():
return redirect("http://www.example.com")—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/tiangolo/fastapi/issues/199, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAINSPSXIAILG372LBLCBC3PTRH5PANCNFSM4HKUV7CQ
.
simple code tested and working, couldn't while afk, the logs show clearly you're redirected to /redirected once you hit /redirect
hope it helps
@app.get("/redirect")
async def redirect():
response = RedirectResponse(url='/redirected')
return response
@app.get("/redirected")
async def redirected():
logger.debug("debug message")
return {"message": "you've been redirected"}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,342 - uvicorn - DEBUG - ('192.168.96.1', 39694) - Connected
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,342 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [6] Initialized {'type': 'http', 'http_version': '1.1', 'server': ('192.168.96.3', 8000), 'client': ('192.168.96.1', 39694), 'scheme': 'http', 'method': 'GET', 'root_path': '', 'path': '/redirect', 'query_string': b'', 'headers': '<...>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,343 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [6] Started task
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,344 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [6] Received {'type': 'http.response.start', 'status': 302, 'headers': '<...>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,344 - uvicorn - INFO - ('192.168.96.1', 39694) - "GET /redirect HTTP/1.1" 302
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,344 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [6] Received {'type': 'http.response.body', 'body': '<0 bytes>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,344 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [6] Completed
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,349 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [7] Initialized {'type': 'http', 'http_version': '1.1', 'server': ('192.168.96.3', 8000), 'client': ('192.168.96.1', 39694), 'scheme': 'http', 'method': 'GET', 'root_path': '', 'path': '/redirected', 'query_string': b'', 'headers': '<...>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,349 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [7] Started task
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,350 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [7] Received {'type': 'http.response.start', 'status': 200, 'headers': '<...>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,350 - uvicorn - INFO - ('192.168.96.1', 39694) - "GET /redirected HTTP/1.1" 200
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,350 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [7] Received {'type': 'http.response.body', 'body': '<36 bytes>'}
backend_1_d9db6d632ea8 | 2019-05-07 06:58:12,351 - uvicorn - DEBUG - ('192.168.96.1', 39694) - ASGI [7] Completed
backend_1_d9db6d632ea8 | 2019-05-07 06:58:17,351 - uvicorn - DEBUG - ('192.168.96.1', 39694) - Disconnected
It works just fine. I have been testing and it's very similar to how Flask redirect works but I don't see how to pass a route object instead of a string path. It would be nice if there was a way to check a route full endpoint (i.e. "localhost:8000/test", instead of only "/test") so we could pass a variable and avoid direct hard coded strings. With flask, we can just pass the BluePrint name and function so it will redirect to the function's path automatically, just like redirect('blueprint.route')
. So I would propose a way that we could just use response = RedirectResponse('app.redirected')
with Starlette. Maybe there is a way to catch the full endpoint that I'm not aware of.
Again Starlette :grin:
 app.url_path_for()Â
It works as well, but seems to not take the subapi path in consideration. This way, if I have a sub api with /subapi
path, when I use RedirectResponse() with url_path_for(), it won't redirect me to /subapi/endpoint
, but to /endpoint
instead.
Can you please provide a failing example?
Thanks for your help here @euri10 !
here's a functioning example with a subapi, if you want @tiangolo I can rewrite the test case and put it in the docs, this was not overlly difficult but getting the right path with url_path_for was funny enough
Thanks @euri10 !
Before you commit the time to adding it in the docs, @marcosmmb, does @euri10's example solve your use case?
Let me copy it inline here:
import logging
from fastapi import FastAPI
from starlette.responses import RedirectResponse
from starlette.testclient import TestClient
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
app = FastAPI()
@app.get("/app")
def read_main():
return {"message": "Hello World from main app"}
subapi = FastAPI(openapi_prefix="/subapi")
@subapi.get("/sub")
async def read_sub():
return {"message": "Hello World from sub API"}
@subapi.get("/redirect")
async def redirect():
url = app.url_path_for("redirected")
response = RedirectResponse(url=url)
return response
@subapi.get("/redirected")
async def redirected():
logger.debug("REDIRECTED")
return {"message": "you've been redirected"}
app.mount("/subapi", subapi)
client = TestClient(app)
def test_redirect_subapi():
url = app.url_path_for("redirect")
response = client.get(url)
assert response.json() == {"message": "you've been redirected"}
Is a TestClient object good enough for production? I'm not that familiarized with Starlette, so it probably is, but I'm really not sure. Also, does this same technique works with routers/blueprints?
The TestClient object is just for demonstrating that it works. You wouldn't use it in production. With the preceding file, you could run this using pytest. @euri10 is just really good at whipping out fully functional demos at the drop of a hat.
@marcosmmb yeah, the TestClient
is for testing as @wshayes says.
Also, the RedirectResponse
docs are here: https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse :rocket:
That should solve this issue. May we close it @marcosmmb ?
Thank you guys for the support!
Most helpful comment
Thanks @euri10 !
Before you commit the time to adding it in the docs, @marcosmmb, does @euri10's example solve your use case?
Let me copy it inline here: