DEV Community

Marcelo Trylesinski
Marcelo Trylesinski

Posted on

How to change FastAPI's swagger favicon?

This is my first blog post, so I'll be succinct. This is more of a step-by-step tutorial, but if you're only interested in the code, feel free to check it.

Let's start defining our goal: we want to change our Swagger UI favicon using a local image.

Step 1: Create our FastAPI application

Let's create a simple FastAPI application with a single endpoint.

# main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def home():
    ...
Enter fullscreen mode Exit fullscreen mode

Let's run our uvicorn server: python -m uvicorn main:app --reload, and use a HTTP client to see what we get from it. I'll be using httpie, but feel free to use curl or any other HTTP client of your choice.

Note that we've used --reload flag on the uvicorn command. To know more about the CLI options, check uvicorn documentation.

❯ http :8000
HTTP/1.1 200 OK
content-length: 4
content-type: application/json
date: Tue, 18 Jan 2022 22:05:38 GMT
server: uvicorn

null

Enter fullscreen mode Exit fullscreen mode

Now that we're sure that our application works, let's go to the next step.

Step 2: Replace the default docs page

Following the ycd snippet on his comment, we'd need to replace the default swagger endpoint. The problem with this approach is that we lose internal logic, as the original endpoint does more than what is in there.

In any case, let's start adding the snippet mentioned above.

from fastapi import FastAPI
from fastapi.openapi.docs import get_swagger_ui_html


app = FastAPI(docs_url=None)


@app.get("/docs", include_in_schema=False)
async def swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url="/openapi.json",
        title="FastAPI",
        swagger_favicon_url="https://placekitten.com/200/300"
    )


@app.get("/")
async def home():
    ...
Enter fullscreen mode Exit fullscreen mode

We still have uvicorn running, and as the reload flag is set, we can see the changes. Go to your browser, and access http://127.0.0.1:8000/docs#/.

As you can see, the favicon has changed.

Step 3: Serve the local favicon

FastAPI is able to serve files from a given directory thanks to Starlette's StaticFiles class, and that's exactly what we're going to do.

Let's create a directory with our favicon, and serve that image.

from fastapi import FastAPI
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.staticfiles import StaticFiles


app = FastAPI(docs_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")


@app.get("/docs", include_in_schema=False)
async def swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url="/openapi.json",
        title="FastAPI",
        swagger_favicon_url="/static/favicon.png"
    )


@app.get("/")
async def home():
    ...
Enter fullscreen mode Exit fullscreen mode

At this point, we need to create a folder called "static", or any other name, just remember to change the name on the directory argument on the StaticFiles instantiation. On this folder, we'll add our image (on our case it's going to be a favicon.png).

Pay attention on the snippet above that we've changed the value of swagger_favicon_url on the get_swagger_ui_html function. If you access the docs page now, you'll see the favicon.

Our goal has been accomplished, but that's not quite the end of it.

Step 4: Improve with details

As I've said at the beginning, the internal FastAPI docs endpoint has more logic than what we've used. So let's add those to our solution.

from fastapi import FastAPI, Request
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")


@app.get("/docs", include_in_schema=False)
async def swagger_ui_html(req: Request) -> HTMLResponse:
    root_path = req.scope.get("root_path", "").rstrip("/")
    openapi_url = root_path + app.openapi_url
    oauth2_redirect_url = app.swagger_ui_oauth2_redirect_url
    if oauth2_redirect_url:
        oauth2_redirect_url = root_path + oauth2_redirect_url
    return get_swagger_ui_html(
        openapi_url=openapi_url,
        title=app.title + " - Swagger UI",
        oauth2_redirect_url=oauth2_redirect_url,
        init_oauth=app.swagger_ui_init_oauth,
        swagger_favicon_url="/static/favicon.png",
        swagger_ui_parameters=app.swagger_ui_parameters,
    )


@app.get("/")
def home():
    return RedirectResponse("/docs")
Enter fullscreen mode Exit fullscreen mode

There are two things to notice on the above improvements: the body of the swagger_ui_html endpoint function has changed, and the / endpoint has been changed to redirect to the /docs endpoint. On the first, we're concerned about the OAuth2 integration with the Swagger UI, and on the second is just to show you something different. :)

That's it.

Thanks for reading until here, and please, give me some feedback and ideas. I'm planning to write daily posts.

Top comments (0)