Skip to content


You can read the request body directly into a file or bytes. This will read the data from the top level request body, and can only support 1 file. To receive multiple files, see the multipart/form-data documentation.

from xpresso import App, FromFile, Path, UploadFile

async def count_bytes_in_file(file: FromFile[UploadFile]) -> int:
    return len(await

app = App(routes=[Path(path="/count-bytes", put=count_bytes_in_file)])


UploadFile is a class provided by Starlette that buffers the data in memory and overflows to disk if the data is larger than a predefined threashold. This prevents a large file from exhausting your hardware's memory.

As bytes

Xpresso can read the entire file into memory if you'd like:

from xpresso import App, FromFile, Path

async def count_bytes_in_file(data: FromFile[bytes]) -> int:
    return len(data)

app = App(routes=[Path(path="/count-bytes", put=count_bytes_in_file)])

This can be convenient if you know the files are not large.

Setting the content-type

You can set the media type via the media_type parameter to File() and enforce it via the enforce_media_type parameter:

from xpresso import App, File, Path, UploadFile
from xpresso.typing import Annotated

async def count_image_bytes(
    file: Annotated[
        File(media_type="image/*", enforce_media_type=True),
) -> int:
    return len(await

app = App(routes=[Path(path="/count-bytes", put=count_image_bytes)])

Media types can be a media type (e.g. image/png) or a media type range (e.g. image/*).

If you do not explicitly set the media type, all media types are accepted. Once you set an explicit media type, that media type in the requests' Content-Type header will be validated on incoming requests, but this behavior can be disabled via the enforce_media_type parameter to File().