Return a Response directly

When you create a FastAPI path operation you can normally return any data from it: a dict, a list, a Pydantic model, a database model, etc.

By default, FastAPI would automatically convert that return value to JSON using the jsonable_encoder.

Then, behind the scenes, it would put that JSON-compatible data (e.g. a dict) inside of a Starlette JSONResponse that would be used to send the response to the client.

But you can return a JSONResponse directly from your path operations.

It might be useful, for example, to return custom headers or cookies.

Starlette Response

In fact, you can return any Starlette Response or any sub-class of it.

Tip

JSONResponse itself is a sub-class of Response.

And when you return a Starlette Response, FastAPI will pass it directly.

It won't do any data conversion with Pydantic models, it won't convert the contents to any type, etc.

This gives you a lot of flexibility. You can return any data type, override any data declaration or validation, etc.

Using the jsonable_encoder in a Response

Because FastAPI doesn't do any change to a Response you return, you have to make sure it's contents are ready for it.

For example, you cannot put a Pydantic model in a JSONResponse without first converting it to a dict with all the data types (like datetime, UUID, etc) converted to JSON-compatible types.

For those cases, you can use the jsonable_encoder to convert your data before passing it to a response:

from datetime import datetime

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from starlette.responses import JSONResponse


class Item(BaseModel):
    title: str
    timestamp: datetime
    description: str = None


app = FastAPI()


@app.put("/items/{id}")
def update_item(id: str, item: Item):
    json_compatible_item_data = jsonable_encoder(item)
    return JSONResponse(content=json_compatible_item_data)

Note

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

Returning a custom Response

The example above shows all the parts you need, but it's not very useful yet, as you could have just returned the item directly, and FastAPI would put it in a JSONResponse for you, converting it to a dict, etc. All that by default.

Now, let's see how you could use that to return a custom response.

Let's say you want to return a response that is not available in the default Starlette Responses.

Let's say that you want to return XML.

You could put your XML content in a string, put it in a Starlette Response, and return it:

from fastapi import FastAPI
from starlette.responses import 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")

Notes

When you return a Response directly its data is not validated, converted (serialized), nor documented automatically.

But you can still document it.

In the next sections you will see how to use/declare these custom Responses while still having automatic data conversion, documentation, etc.

You will also see how to use them to set response Headers and Cookies.