Fastapi: [QUESTION] How to redirect to another page

Created on 3 May 2019  Â·  13Comments  Â·  Source: tiangolo/fastapi

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")
question

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:

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"}

All 13 comments

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!

Was this page helpful?
0 / 5 - 0 ratings