How to return a custom 404 Not Found page using FastAPI?

ghz 1years ago ⋅ 9934 views

Question

I am making a rick roll site for Discord and I would like to redirect to the rick roll page on 404 response status codes.

I've tried the following, but didn't work:

 @app.exception_handler(fastapi.HTTPException)
 async def http_exception_handler(request, exc):
     ...

Answer

Update

A more elegant solution would be to use a custom exception handler, passing the status code of the exception you would like to handle, as shown below:

from fastapi.responses import RedirectResponse
from fastapi.exceptions import HTTPException

@app.exception_handler(404)
async def not_found_exception_handler(request: Request, exc: HTTPException):
    return RedirectResponse('https://fastapi.tiangolo.com')

or, use the exception_handlers parameter of the FastAPI class like this:

async def not_found_error(request: Request, exc: HTTPException):
    return RedirectResponse('https://fastapi.tiangolo.com')

exception_handlers = {404: not_found_error}
app = FastAPI(exception_handlers=exception_handlers)

Note: In the examples above, a RedirectResponse is returned, as OP asked for redirecting the user. However, you could instead return some custom Response, [HTMLResponse](https://fastapi.tiangolo.com/advanced/custom-response/#html- response) or [Jinja2 TemplateResponse](https://fastapi.tiangolo.com/advanced/templates/#using- jinja2templates), as demosntrated in the example below.

Working Example

app.py

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.exceptions import HTTPException


async def not_found_error(request: Request, exc: HTTPException):
    return templates.TemplateResponse('404.html', {'request': request}, status_code=404)


async def internal_error(request: Request, exc: HTTPException):
    return templates.TemplateResponse('500.html', {'request': request}, status_code=500)

    
templates = Jinja2Templates(directory='templates')

exception_handlers = {
    404: not_found_error,
    500: internal_error
}

app = FastAPI(exception_handlers=exception_handlers)

templates/ 404.html

<!DOCTYPE html>
<html>
   <title>Not Found</title>
   <body>
      <h1>Not Found</h1>
      <p>The requested resource was not found on this server.</p>
   </body>
</html>

templates/ 500.html

<!DOCTYPE html>
<html>
   <title>Internal Server Error</title>
   <body>
      <h1>Internal Server Error</h1>
      <p>The server encountered an internal error or 
         misconfiguration and was unable to complete your request.
      </p>
   </body>
</html>

Original answer

You would need to create a [middleware](https://fastapi.tiangolo.com/tutorial/middleware/#create-a- middleware) and check for the status_code of the response. If it is 404, then return a [RedirectResponse](https://fastapi.tiangolo.com/es/advanced/custom- response/#redirectresponse). Example:

from fastapi import Request
from fastapi.responses import RedirectResponse

@app.middleware("http")
async def redirect_on_not_found(request: Request, call_next):
    response = await call_next(request)
    if response.status_code == 404:
        return RedirectResponse("https://fastapi.tiangolo.com")
    else:
        return response