Custom Response Class

Warning

This is a rather advanced topic.

If you are starting with FastAPI, you might not need this.

By default, FastAPI will return the responses using Starlette's JSONResponse.

You can override it by returning a Response directly, as seen in a previous section.

But if you return a Response directly, the data won't be automatically converted, and the documentation won't be automatically generated (for example, including the specific "media type", in the HTTP header Content-Type).

But you can also declare the Response that you want to be used, in the path operation decorator.

The contents that you return from your path operation function will be put inside of that Response.

And if that Response has a JSON media type (application/json), like is the case with the JSONResponse and UJSONResponse, the data you return will be automatically converted (and filtered) with any Pydantic response_model that you declared in the path operation decorator.

Use UJSONResponse

For example, if you are squeezing performance, you can install and use ujson and set the response to be Starlette's UJSONResponse.

Import the Response class (sub-class) you want to use and declare it in the path operation decorator.

from fastapi import FastAPI
from starlette.responses import UJSONResponse

app = FastAPI()


@app.get("/items/", response_class=UJSONResponse)
async def read_items():
    return [{"item_id": "Foo"}]

Note

Notice that you import it directly from starlette.responses, not from fastapi.

Info

The parameter response_class will also be used to define the "media type" of the response.

In this case, the HTTP header Content-Type will be set to application/json.

And it will be documented as such in OpenAPI.

HTML Response

To return a response with HTML directly from FastAPI, use HTMLResponse.

  • Import HTMLResponse.
  • Pass HTMLResponse as the parameter content_type of your path operation.
from fastapi import FastAPI
from starlette.responses import HTMLResponse

app = FastAPI()


@app.get("/items/", response_class=HTMLResponse)
async def read_items():
    return """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """

Note

Notice that you import it directly from starlette.responses, not from fastapi.

Info

The parameter response_class will also be used to define the "media type" of the response.

In this case, the HTTP header Content-Type will be set to text/html.

And it will be documented as such in OpenAPI.

Return a Starlette Response

As seen in another section, you can also override the response directly in your path operation, by returning it.

The same example from above, returning an HTMLResponse, could look like:

from fastapi import FastAPI
from starlette.responses import HTMLResponse

app = FastAPI()


@app.get("/items/")
async def read_items():
    html_content = """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """
    return HTMLResponse(content=html_content, status_code=200)

Warning

A Response returned directly by your path operation function won't be documented in OpenAPI (for example, the Content-Type won't be documented) and won't be visible in the automatic interactive docs.

Info

Of course, the actual Content-Type header, status code, etc, will come from the Response object your returned.

Document in OpenAPI and override Response

If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the response_class parameter AND return a Response object.

The response_class will then be used only to document the OpenAPI path operation, but your Response will be used as is.

Return an HTMLResponse directly

For example, it could be something like:

from fastapi import FastAPI
from starlette.responses import HTMLResponse

app = FastAPI()


def generate_html_response():
    html_content = """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """
    return HTMLResponse(content=html_content, status_code=200)


@app.get("/items/", response_class=HTMLResponse)
async def read_items():
    return generate_html_response()

In this example, the function generate_html_response() already generates a Starlette Response instead of the HTML in a str.

By returning the result of calling generate_html_response(), you are already returning a Response that will override the default FastAPI behavior.

But as you passed the HTMLResponse in the response_class, FastAPI will know how to document it in OpenAPI and the interactive docs as HTML with text/html:

Additional documentation

You can also declare the media type and many other details in OpenAPI using responses: Additional Responses in OpenAPI.