Sling Academy
Home/FastAPI/How to Implement Redirects in FastAPI (2 Ways)

How to Implement Redirects in FastAPI (2 Ways)

Last updated: September 03, 2023

Redirect means sending users from one URL to another, usually after performing some action or checking some condition (such as authentication, payment, etc.). This concise, example-based article will walk you through a couple of different ways to create redirects in FastAPI (a modern Python web framework).

Using RedirectResponse (recommended)

This solution uses the RedirectResponse class from fastapi.responses to return a response that redirects the client to a different URL. It takes 2 main parameters: url and status_code:

  • url: Determines the destination URL that you want the client to go to.
  • status_code: Set the HTTP status code that indicates the type of redirect. The default value is 307 (Temporary Redirect).

There are different types of redirects, but the most common ones are:

  • 301 Moved Permanently: This means that the resource has been permanently moved to a new location, and the browser should always use the new URL in the future.
  • 302 Found: This means that the resource has been temporarily moved to a new location, but the browser may use the old URL again in the future.
  • 303 See Other: This means that the resource has been successfully processed, and the browser should go to a different URL to get the result.

Code example:

from fastapi import FastAPI
from fastapi.responses import RedirectResponse
import starlette.status as status

app = FastAPI()


@app.get("/")
async def main():
    # Redirect to /docs (relative URL)
    return RedirectResponse(url="/docs", status_code=status.HTTP_302_FOUND)


@app.get("/sling-academy")
async def sling_academy():
    # Redirect to an absolute URL
    return RedirectResponse(
        url="https://api.slingacademy.com", status_code=status.HTTP_302_FOUND
    )

Now get the app up and running by executing this command:

uvicorn main:app --reload

Then go to http://localhost:8000 and http://localhost:8000/sling-academy to test it out.

This approach is simple and easy to use, and it supports both relative and absolute URLs.

Using Request.scope (advanced)

This solution uses the request.scope attribute to modify the request path, headers, and parameters before processing it by another path operation function. It does not require sending a redirection response to the client. However, there are some trade-offs you should be aware of:

  • This approach requires accessing and modifying the low-level request.scope attribute, which may not be documented or stable.
  • May cause unexpected behavior or errors if not handled carefully.
  • The code is longer and more complicated than using RedirectResponse.

The steps:

  1. Import Request from fastapi.
  2. Define a middleware function that takes a request object and a call_next function as arguments.
  3. In the middleware function, check if the request path matches a certain format or condition.
  4. If yes, change the request.scope['path'] value to the target path.
  5. Optionally, you can also modify the request.scope['headers'] and request.scope['query_string'] values to change the request headers and parameters.
  6. Return the result of calling call_next(request).
  7. Register the middleware function with app.middleware("http").

Complete example:

from fastapi import FastAPI, Request

app = FastAPI()

# Define a middleware that will reroute all requests to /old to /new, and change the headers and parameters
@app.middleware("http")
async def reroute_middleware(request: Request, call_next):
    if request.url.path.startswith("/old"):
        # Change the request path
        request.scope["path"] = request.url.path.replace("/old", "/new")

        # Change the request headers
        headers = dict(request.scope["headers"])
        headers[b"x-rerouted"] = b"yes"
        request.scope["headers"] = [(k, v) for k, v in headers.items()]

        # Change the request parameters
        request.scope["query_string"] = b"sling=academy"
    response = await call_next(request)
    return response


@app.get("/old")
async def old():
    return "This is the old endpoint"


@app.get("/new")
async def new(request: Request):
    return {
        "msg": "This is the new endpoint",
        "headers": request.headers,
        "params": request.query_params,
    }

Conclusion

You’ve learned 2 different techniques to make redirection in FastAPI. In most cases, you’ll only need the first one. However, the second technique is worth knowing. This tutorial ends here. Happy coding & have a nice day!

Next Article: FastAPI + SQLAlchemy: Using cursor-based pagination

Previous Article: How to Run Background Tasks in FastAPI (2 Ways)

Series: FastAPI Request & Response Tutorials

FastAPI

You May Also Like

  • Popular useful built-in Jinja filters you should know
  • How to remove consecutive whitespace in rendered Jinja pages
  • How to format large numbers with thousand separators in Jinja template
  • How to format date time in Jinja templates
  • FastAPI + Jinja: How to create custom filters
  • How to pass variables from Python (FastAPI) to Jinja
  • How to decode Jinja response to string
  • How to create and use macros in Jinja
  • How to use namespace in Jinja
  • How to use if/ else in Jinja
  • How to use loops in Jinja
  • FastAPI + SQLAlchemy: Using cursor-based pagination
  • FastAPI: How to use macros in Jinja templates
  • Fixing Common Swagger UI Errors in FastAPI
  • FastAPI Error: 307 Temporary Redirect – Causes and Solutions
  • FastAPI Error: Expected UploadFile, received ‘str’
  • Resolving FastAPI ImportError: No Known Parent Package
  • FastAPI Error: No module named ‘pydantic_core._pydantic_core’
  • Resolving FastAPI 422 Error: Value is not a valid dict