FastAPI

FastAPI is a Python API framework based on type hints, with data validation and OpenAPI schema generation. Use imgproxykit’s dependency integration to inject a client into route handlers and return image URLs and named variants in typed response models.

Explore the FastAPI tutorial and the project on GitHub.

Installation

In your FastAPI project, install imgproxykit with FastAPI support:

uv add 'imgproxykit[fastapi]'
poetry add 'imgproxykit[fastapi]'
pip install 'imgproxykit[fastapi]'

Register a client

Call add_imgproxy() while creating the application. Keep the returned dependency for use in your routes:

from typing import Annotated, Final

from fastapi import Depends, FastAPI
from pydantic import BaseModel

from imgproxykit import Client, Transform
from imgproxykit.integrations.fastapi import add_imgproxy

_SOURCE_URL: Final = 'https://originals.example.com/photo.jpg'
_THUMBNAIL: Final = Transform(width=300, format='webp')

app = FastAPI()
get_imgproxy = add_imgproxy(app, Client('https://imgproxy.example.com'))  # (1)!


class ImageResponse(BaseModel):
    """Generated image URL."""

    image: str


@app.get('/image')
async def get_image(
    imgproxy: Annotated[Client, Depends(get_imgproxy)],  # (2)!
) -> ImageResponse:
    """Return a transformed image URL."""
    image = imgproxy.url(_SOURCE_URL, transform=_THUMBNAIL)
    return ImageResponse(image=image)
  1. Register the client once and keep the returned dependency. The client is stored on app.state.imgproxykit_client.

  2. Inject the registered client into the route handler. The same client is reused across requests.

URL generation makes no network requests. See Client to configure signing credentials.

Return variants

Declare image variants as a dataclass and use it as a field in a Pydantic response model:

from dataclasses import dataclass
from typing import Annotated, Final

from fastapi import Depends, FastAPI
from pydantic import BaseModel

from imgproxykit import Client, Transform
from imgproxykit.integrations.fastapi import add_imgproxy

_SOURCE_URL: Final = 'https://originals.example.com/photo.jpg'
_BASE: Final = Transform(format='webp')

app = FastAPI()
get_imgproxy = add_imgproxy(app, Client('https://imgproxy.example.com'))


@dataclass(frozen=True, slots=True)
class ProductImages:
    """Declare the image response fields and their transformations."""

    thumbnail: Annotated[str, _BASE.extend(width=320)]  # (1)!
    preview: Annotated[str, _BASE.extend(width=1280)]


class ImageResponse(BaseModel):
    """Named image variants."""

    images: ProductImages  # (2)!


@app.get('/image')
async def get_image(
    imgproxy: Annotated[Client, Depends(get_imgproxy)],
) -> ImageResponse:
    """Return named image variants."""
    images = imgproxy.variants(_SOURCE_URL, variants=ProductImages)  # (3)!
    return ImageResponse(images=images)
  1. Associate each URL field with a transformation using Annotated.

  2. Include the dataclass in the response model. FastAPI documents its string fields in the OpenAPI schema.

  3. Generate a dataclass instance containing the URLs. Pydantic serializes it as a nested object.

See Return a dataclass for declaration requirements.

Multiple clients

Register each client separately and use its returned dependency in Depends. This example injects both a signed and an unsigned client:

from typing import Annotated, Final

from fastapi import Depends, FastAPI
from pydantic import BaseModel

from imgproxykit import Client
from imgproxykit.integrations.fastapi import add_imgproxy

_SOURCE_URL: Final = 'https://originals.example.com/photo.jpg'

app = FastAPI()
get_signed_imgproxy = add_imgproxy(  # (1)!
    app,
    Client(
        'https://imgproxy.example.com',
        key='736563726574',
        salt='73616c74',
    ),
)
get_unsigned_imgproxy = add_imgproxy(
    app,
    Client('https://imgproxy.example.com'),
    name='unsigned_imgproxy',  # (2)!
)


class ImageUrls(BaseModel):
    """Signed and unsigned image URLs."""

    signed: str
    unsigned: str


@app.get('/images')
async def get_images(
    signed: Annotated[Client, Depends(get_signed_imgproxy)],  # (3)!
    unsigned: Annotated[Client, Depends(get_unsigned_imgproxy)],
) -> ImageUrls:
    """Build image URLs with each client's signing configuration."""
    return ImageUrls(
        signed=signed.url(_SOURCE_URL),
        unsigned=unsigned.url(_SOURCE_URL),
    )
  1. Register a signed client under the default name. Replace the example key and salt with your imgproxy credentials.

  2. Give the unsigned client a separate name on app.state.

  3. Use each registration’s returned dependency to inject its client.

Registering a name already present on app.state raises ValueError. Unsigned URLs require an imgproxy server configured to accept them.

Next steps