Skip to content

Custom Response - HTML, Stream, File, others

By default, FastAPI will return the responses using JSONResponse.

You can override it by returning a Response directly as seen in Return a Response directly.

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 as part of the generated OpenAPI).

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.

Note

If you use a response class with no media type, FastAPI will expect your response to have no content, so it will not document the response format in its generated OpenAPI docs.

Use ORJSONResponse

For example, if you are squeezing performance, you can install and use orjson and set the response to be ORJSONResponse.

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

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI()


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

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.

Tip

The ORJSONResponse is currently only available in FastAPI, not in Starlette.

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 fastapi.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>
    """

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 Response

As seen in Return a Response directly, 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 fastapi.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 fastapi.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 and returns a Response instead of returning 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 too, FastAPI will know how to document it in OpenAPI and the interactive docs as HTML with text/html:

Available responses

Here are some of the available responses.

Have in mind that you can use Response to return anything else, or even create a custom sub-class.

Technical Details

You could also use from starlette.responses import HTMLResponse.

FastAPI provides the same starlette.responses as fastapi.responses just as a convenience for you, the developer. But most of the available responses come directly from Starlette.

Response

The main Response class, all the other responses inherit from it.

You can return it directly.

It accepts the following parameters:

  • content - A str or bytes.
  • status_code - An int HTTP status code.
  • headers - A dict of strings.
  • media_type - A str giving the media type. E.g. "text/html".

FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the media_type and appending a charset for text types.

from fastapi import FastAPI, Response

app = FastAPI()


@app.get("/legacy/")
def get_legacy_data():
    data = """<?xml version="1.0"?>
    <shampoo>
    <Header>
        Apply shampoo here.
    </Header>
    <Body>
        You'll have to use soap here.
    </Body>
    </shampoo>
    """
    return Response(content=data, media_type="application/xml")

HTMLResponse

Takes some text or bytes and returns an HTML response, as you read above.

PlainTextResponse

Takes some text or bytes and returns an plain text response.

from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI()


@app.get("/", response_class=PlainTextResponse)
async def main():
    return "Hello World"

JSONResponse

Takes some data and returns an application/json encoded response.

This is the default response used in FastAPI, as you read above.

ORJSONResponse

A fast alternative JSON response using orjson, as you read above.

UJSONResponse

An alternative JSON response using ujson.

Warning

ujson is less careful than Python's built-in implementation in how it handles some edge-cases.

from fastapi import FastAPI
from fastapi.responses import UJSONResponse

app = FastAPI()


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

Tip

It's possible that ORJSONResponse might be a faster alternative.

RedirectResponse

Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.

from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/typer")
async def read_typer():
    return RedirectResponse("https://typer.tiangolo.com")

StreamingResponse

Takes an async generator or a normal generator/iterator and streams the response body.

from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()


async def fake_video_streamer():
    for i in range(10):
        yield b"some fake video bytes"


@app.get("/")
async def main():
    return StreamingResponse(fake_video_streamer())

Using StreamingResponse with file-like objects

If you have a file-like object (e.g. the object returned by open()), you can return it in a StreamingResponse.

This includes many libraries to interact with cloud storage, video processing, and others.

from fastapi import FastAPI
from fastapi.responses import StreamingResponse

some_file_path = "large-video-file.mp4"
app = FastAPI()


@app.get("/")
def main():
    file_like = open(some_file_path, mode="rb")
    return StreamingResponse(file_like, media_type="video/mp4")

Tip

Notice that here as we are using standard open() that doesn't support async and await, we declare the path operation with normal def.

FileResponse

Asynchronously streams a file as the response.

Takes a different set of arguments to instantiate than the other response types:

  • path - The filepath to the file to stream.
  • headers - Any custom headers to include, as a dictionary.
  • media_type - A string giving the media type. If unset, the filename or path will be used to infer a media type.
  • filename - If set, this will be included in the response Content-Disposition.

File responses will include appropriate Content-Length, Last-Modified and ETag headers.

from fastapi import FastAPI
from fastapi.responses import FileResponse

some_file_path = "large-video-file.mp4"
app = FastAPI()


@app.get("/")
async def main():
    return FileResponse(some_file_path)

Additional documentation

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