Search code examples
pythonexceptionhttp-status-code-404fastapistarlette

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


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):
     ...

Solution

  • 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 or Jinja2 TemplateResponse, 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 and check for the status_code of the response. If it is 404, then return a 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