Skip to content

FastAPI configuration

This module defines two building blocks to configure a FastAPI application in a composable, dependency-injection-friendly way:

  • FastApiSettings: a dataclass that carries basic application metadata (title, version, debug) and is designed to be provided by the pico-ioc container.
  • FastApiConfigurer: a protocol (interface) for pluggable components that can mutate/configure a FastAPI app. Multiple configurers can be registered and executed in a deterministic order using a priority.

Use these together to bootstrap your app with clear separation between application settings and configuration steps such as adding middleware, routers, and event handlers.

FastApiSettings

What it is: - A @configured dataclass that holds basic FastAPI settings. - Automatically loaded from configuration sources (YAML, env, dict) via the fastapi prefix.

Fields: - title: str — The application title (propagated to FastAPI). - version: str — The application version (propagated to FastAPI). - debug: bool — Whether to run FastAPI in debug mode. - telemetry: dict — Passed to FastAPI's built-in OpenTelemetry (FastAPI >= 0.142; older versions ignore it). Default {"auto_configure": False}.

Telemetry (FastAPI >= 0.142)

FastAPI 0.142 instruments every app with OpenTelemetry by default and, when OTEL_EXPORTER_OTLP_ENDPOINT is set, appends its own OTLP exporter to the global providers when the app starts. If your application (or pico-otel) already configured an exporter, every span would be exported twice. pico-fastapi therefore defaults telemetry to {"auto_configure": False}: FastAPI still records its spans against whatever providers you configured, but never adds exporters of its own.

To let FastAPI configure exporting itself (no other OpenTelemetry setup in the app, fastapi[standard] installed), opt back in:

fastapi:
  telemetry:
    auto_configure: true

Any key FastAPI documents for telemetry (tracing, metrics, logs, operation_spans, ...) can be set the same way. Setting telemetry replaces the default dict, so keep auto_configure: false if you only want to change another key.

How to use: - Provide a configuration source with a fastapi prefix when initializing the container. - FastApiSettings is automatically populated and injected into the FastAPI app factory.

Example:

# application.yaml
fastapi:
  title: Example API
  version: 1.0.0
  debug: true

from pico_boot import init
from pico_ioc import configuration, YamlTreeSource
from fastapi import FastAPI

config = configuration(YamlTreeSource("application.yaml"))
container = init(modules=["myapp"], config=config)
app = container.get(FastAPI)

# app.title == "Example API"
# app.version == "1.0.0"
# app.debug == True

FastApiConfigurer protocol

What it is: - A protocol defining a uniform way to configure a FastAPI app. - Lets you register multiple independent configurers and run them in a defined order.

Members: - priority: int — A numeric priority used to sort configurers. Negative = outer middleware, non-negative = inner middleware. - configure_app(self, app) -> None: Receives the FastAPI app instance and performs configuration (e.g., include routers, add middleware, register events).

Typical use cases: - Add middleware (CORS, logging, tracing). - Mount sub-apps and static files. - Register error handlers and event handlers.

Example: implement and register configurers

from pico_ioc import component
from pico_fastapi import FastApiConfigurer
from fastapi import FastAPI

@component
class LoggingConfigurer(FastApiConfigurer):
    priority = -10  # Outer middleware

    def configure_app(self, app: FastAPI) -> None:
        @app.middleware("http")
        async def log_requests(request, call_next):
            response = await call_next(request)
            return response

@component
class HealthRouteConfigurer(FastApiConfigurer):
    priority = 0

    def configure_app(self, app: FastAPI) -> None:
        from fastapi import APIRouter
        router = APIRouter()

        @router.get("/health")
        def health():
            return {"status": "ok"}

        app.include_router(router, prefix="/api")

Configurers are automatically discovered by the container. Just include the module in init(modules=[...]).

Notes on priority: - Negative priority: outer middleware (runs before PicoScopeMiddleware). - Non-negative priority: inner middleware (runs after PicoScopeMiddleware). - Within the same group, lower numbers run first.

Testing a configurer:

from fastapi import FastAPI

def test_health_route_configurer():
    app = FastAPI()
    cfg = HealthRouteConfigurer()
    cfg.configure_app(app)

    routes = {r.path for r in app.routes}
    assert "/api/health" in routes

Summary: - FastApiSettings provides injectable core settings for FastAPI instantiation via @configured. - FastApiConfigurer defines a simple contract for modular, ordered app configuration. - Register configurers as @component classes; pico-ioc discovers and applies them automatically.


Auto-generated API

pico_fastapi.config

Configuration primitives for pico-fastapi.

Defines :class:FastApiSettings (application metadata loaded from config) and the :class:FastApiConfigurer protocol (pluggable setup hooks with priority-based ordering).

FastApiConfigurer

Bases: Protocol

Protocol for pluggable FastAPI configuration hooks.

Implement this protocol to add middleware, mount sub-apps, register error handlers, or perform any other app-level setup. Configurers are discovered automatically by pico-ioc when decorated with @component.

The priority attribute controls ordering relative to PicoScopeMiddleware:

  • priority < 0 -- outer middleware, applied before the scope middleware (e.g. CORS, session).
  • priority >= 0 -- inner middleware, applied after the scope middleware (e.g. auth, business-logic hooks).

Within the same group, lower values execute first.

Attributes:

Name Type Description
priority int

Integer that determines execution order. Defaults to 0.

Example

.. code-block:: python

from pico_ioc import component
from pico_fastapi import FastApiConfigurer
from fastapi import FastAPI

@component
class CORSConfigurer(FastApiConfigurer):
    priority = -100

    def configure_app(self, app: FastAPI) -> None:
        from fastapi.middleware.cors import CORSMiddleware
        app.add_middleware(
            CORSMiddleware,
            allow_origins=["*"],
        )
Source code in src/pico_fastapi/config.py
@runtime_checkable
class FastApiConfigurer(Protocol):
    """Protocol for pluggable FastAPI configuration hooks.

    Implement this protocol to add middleware, mount sub-apps, register
    error handlers, or perform any other app-level setup.  Configurers are
    discovered automatically by pico-ioc when decorated with ``@component``.

    The ``priority`` attribute controls ordering relative to
    ``PicoScopeMiddleware``:

    - **priority < 0** -- *outer* middleware, applied **before** the scope
      middleware (e.g. CORS, session).
    - **priority >= 0** -- *inner* middleware, applied **after** the scope
      middleware (e.g. auth, business-logic hooks).

    Within the same group, lower values execute first.

    Attributes:
        priority: Integer that determines execution order.  Defaults to ``0``.

    Example:
        .. code-block:: python

            from pico_ioc import component
            from pico_fastapi import FastApiConfigurer
            from fastapi import FastAPI

            @component
            class CORSConfigurer(FastApiConfigurer):
                priority = -100

                def configure_app(self, app: FastAPI) -> None:
                    from fastapi.middleware.cors import CORSMiddleware
                    app.add_middleware(
                        CORSMiddleware,
                        allow_origins=["*"],
                    )
    """

    @property
    def priority(self) -> int:
        return 0

    def configure_app(self, app: FastAPI) -> None:
        """Apply configuration to the FastAPI application.

        Args:
            app: The FastAPI application instance to configure.
        """
        ...

configure_app(app)

Apply configuration to the FastAPI application.

Parameters:

Name Type Description Default
app FastAPI

The FastAPI application instance to configure.

required
Source code in src/pico_fastapi/config.py
def configure_app(self, app: FastAPI) -> None:
    """Apply configuration to the FastAPI application.

    Args:
        app: The FastAPI application instance to configure.
    """
    ...

FastApiSettings dataclass

Type-safe application settings for the FastAPI instance.

Populated automatically from configuration sources (YAML, env, dict) using the fastapi prefix via pico-ioc's @configured decorator. The FastApiAppFactory converts these fields into keyword arguments for the FastAPI() constructor.

Attributes:

Name Type Description
title str

API title shown in the OpenAPI docs.

version str

API version string.

debug bool

Enable FastAPI debug mode.

telemetry Dict[str, Any]

Passed to FastAPI's built-in OpenTelemetry (FastAPI >= 0.142; ignored by older versions). The default stops FastAPI from adding its own OTLP exporter on top of the providers your app configures.

Example

.. code-block:: yaml

# application.yaml
fastapi:
  title: My API
  version: 2.0.0
  debug: true
Source code in src/pico_fastapi/config.py
@configured(target="self", prefix="fastapi", mapping="tree")
@dataclass
class FastApiSettings:
    """Type-safe application settings for the FastAPI instance.

    Populated automatically from configuration sources (YAML, env, dict)
    using the ``fastapi`` prefix via pico-ioc's ``@configured`` decorator.
    The ``FastApiAppFactory`` converts these fields into keyword arguments
    for the ``FastAPI()`` constructor.

    Attributes:
        title: API title shown in the OpenAPI docs.
        version: API version string.
        debug: Enable FastAPI debug mode.
        telemetry: Passed to FastAPI's built-in OpenTelemetry (FastAPI >= 0.142;
            ignored by older versions). The default stops FastAPI from adding
            its own OTLP exporter on top of the providers your app configures.

    Example:
        .. code-block:: yaml

            # application.yaml
            fastapi:
              title: My API
              version: 2.0.0
              debug: true
    """

    title: str = "Pico-FastAPI App"
    version: str = "1.0.0"
    debug: bool = False
    telemetry: Dict[str, Any] = field(default_factory=lambda: {"auto_configure": False})