Skip to main content

neva-fastapi

The FastAPI integration for the Neva framework. It marries FastAPI to neva's dishka-based dependency-injection container so that route handlers resolve injected services, while keeping all HTTP concerns out of the framework-agnostic python-neva core.

Most consumers pull this in transitively via the python-neva[fastapi] extra rather than depending on it directly.

What it provides

Everything is re-exported from neva.fastapi:

  • App — a subclass of fastapi.FastAPI that owns a neva.arch.Application (the DI container) and drives it: builds the container, reads app metadata from neva config (app.*), wires neva providers' lifespan() hooks, and installs per-request DI scoping middleware.
  • APIRouter — a subclass of fastapi.APIRouter that forces route_class=DishkaRoute so injection works inside handlers.
  • Inject — a re-export of dishka.FromDishka. Annotate handler params as Inject[SomeService]. Inject only works on this package's APIRouter (or App's routes) — a vanilla fastapi.APIRouter lacks DishkaRoute and injection silently won't happen.
  • route_template — (scope) -> str | None, the matched route's path template with router prefixes and mount points applied ("/api/v1/users/{id}"), or None when nothing matched. A pure function over the ASGI scope, so it works with a vanilla fastapi.APIRouter too. Written for neva-asgi[otel]'s tracing middleware, which takes it as an injected callable — a tracer needs the template rather than the resolved path, or every request becomes its own operation and no endpoint can be aggregated. This package depends on no OpenTelemetry to provide it, not even optionally.
  • HttpAppConfig — a TypedDict naming the app.* config keys this package reads, so a type checker catches the typos that a Result-based lookup with a default would otherwise swallow.

neva is a namespace package (no top-level neva/__init__.py); this repo owns neva/fastapi/ and shares the neva.* namespace with python-neva.

Application metadata

The OpenAPI document's title and version, the debug flag and the three documentation URLs come from the app config namespace rather than the constructor:

# src/config/app.py
config = {
    "title": "Billing",
    "version": "2.1.0",
    "docs_url": "/documentation",
}

HttpAppConfig declares those six keys — title, debug, version, openapi_url, docs_url, redoc_url — and nothing else. The app namespace is shared, and each package declares only what it reads: the core owns key, previous_keys and providers. A TypedDict is closed, so annotate a real config/app.py with a shape that inherits from each package's:

from neva.arch import AppConfig
from neva.fastapi import HttpAppConfig


class ServiceAppConfig(HttpAppConfig, AppConfig): ...


config: ServiceAppConfig = {"title": "Billing", "providers": [...]}

Annotating with HttpAppConfig alone rejects providers; that is the ownership rule working, not a defect. Unset keys fall back to Neva Application, 0.1.0, debug off, /openapi.json, /docs and /redoc.

Testing helpers

neva.fastapi.testing.HttpTestCase is a neva.testing.TestCase whose application is the one your App owns, booted through the App's own lifespan, with an http_client fixture over it.

from neva.fastapi.testing import HttpTestCase


class TestActors(HttpTestCase):
    @override
    @classmethod
    def create_app(cls, config_path: Path) -> App:
        app = App(config_path=config_path)
        _ = app.register(ActorProvider)
        app.include_router(router)
        return app

    async def test_it_lists(self, http_client: AsyncClient) -> None:
        assert (await http_client.get("/actors")).status_code == 200

Register providers and include routers in create_app: it runs before the boot, and Application.register refuses once the application is booted.

The webapp / http_client fixtures and the neva.fastapi.fixtures plugin were removed in 2.0.0. webapp was a synchronous fixture, so nothing ever entered the app's lifespan — it handed back an unbooted app with no state.dishka_container and no provider hooks run.

Develop

uv sync          # install/refresh deps
poe lint         # ruff check
poe fmt          # ruff format
poe tc           # pyrefly check
poe test         # pytest
poe test-cov     # pytest --cov=neva --cov-report=term-missing

asyncio_mode = "auto" is set, so async tests need no @pytest.mark.asyncio.

Contributing

Commits follow Conventional Commits with gitmoji prefixes, enforced by cz_gitmoji. Commitizen is a dev dependency — run cz commit for the guided wizard, or format manually as :gitmoji: type(scope): subject.

Releases are cut per-repo with commitizen from the repo root:

cz bump                          # bump version in pyproject, write CHANGELOG, tag v<version>
git push --follow-tags origin main
uv build && uv publish           # build + publish the wheel/sdist

cz bump derives the level from the commits since the last tag, updates CHANGELOG.md, and runs scripts/retag-with-changelog.sh to rewrite the new tag with the rendered changelog as its annotation.

Metadata

Release files for neva-fastapi 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for neva-fastapi 2.1.0
File Size Uploaded
neva_fastapi-2.1.0.tar.gz 125.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for neva-fastapi 2.1.0
File Interpreter ABI Platform
neva_fastapi-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 147.3 kB

Release files / neva_fastapi-2.1.0.tar.gz

Download URL neva_fastapi-2.1.0.tar.gz
Size 125.9 kB
Tags Source
SHA-256 checksum
How to use checksums
eeccfe6283325c6fddc114e2c66304e2442d8206599b28668ec44e10a4bfed08
BLAKE2b-256 checksum
How to use checksums
5da264b1f07b16d8b94a7f7c9084415bae2c40b295f83053697c6d4b578f2987
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.22

Release files / neva_fastapi-2.1.0-py3-none-any.whl

Download URL neva_fastapi-2.1.0-py3-none-any.whl
Size 21.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ea9bb0d36ef9b5e199db89bb5998dd9966461a274b2cf3e6645860076c2b84d
BLAKE2b-256 checksum
How to use checksums
1b0b13d0020d95b6fe932b9b4a152851231dd18b00e34acbc8a7f2bdc544ae82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.22

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page