Skip to main content

🚀 fastapi-dishka

PyPI - Version PyPI - Wheel PyPI - Status PyPI - License PyPI - Downloads PyPI - Format codecov Python 3.13+ FastAPI

🍽️ Serve your FastAPI dependencies with style! A delightful integration between FastAPI and Dishka that makes dependency injection feel like a five-star dining experience.

✨ What is this magic?

fastapi-dishka bridges the gap between FastAPI and Dishka, bringing you:

  • 🔄 Auto-registration - Routers and middleware register themselves like magic
  • 🎯 Provider-first design - Your providers are first-class citizens
  • 🧩 Seamless integration - Works with existing FastAPI and Dishka code
  • 🚀 Zero boilerplate - Less setup, more building awesome stuff
  • 🔒 Type-safe - Full type hints and mypy support
  • ⚡ High performance - Built on FastAPI and Dishka's solid foundations

🛠️ Installation

Get started in seconds:

pip install fastapi-dishka

Or if you're feeling fancy with poetry:

poetry add fastapi-dishka

🎬 Quick Start

Here's how easy it is to get rolling:

from dishka import Scope, provide, FromDishka
from fastapi_dishka import App, APIRouter, provide_router, Provider

# 📦 Create your service
class GreetingService:
    def greet(self, name: str) -> str:
        return f"Hello, {name}! 👋"

# 🛣️ Create your router
router = APIRouter(prefix="/api")

@router.get("/greet/{name}")
async def greet_endpoint(name: str, service: FromDishka[GreetingService]) -> dict:
    return {"message": service.greet(name)}

# 🏭 Create your provider
class AppProvider(Provider):
    scope = Scope.APP

    # 🎯 Auto-register the router
    greeting_router = provide_router(router)

    # 📋 Provide your services
    greeting_service = provide(GreetingService, scope=Scope.APP)

# 🚀 Launch your app
app = App("My Awesome API", "1.0.0", AppProvider())

if __name__ == "__main__":
    app.start_sync()  # 🔥 Your API is now running!

That's it! Your API is running with auto-registered routes and dependency injection. 🎉

🎭 Features & Examples

🔄 Auto-Router Registration

Say goodbye to manually registering every router:

from fastapi_dishka import provide_router, Provider

class MyProvider(Provider):
    # ✨ These routers register themselves automatically
    users_router = provide_router(users_router)
    posts_router = provide_router(posts_router)
    comments_router = provide_router(comments_router)

🛡️ Middleware with Dependency Injection

Create powerful middleware that can inject dependencies:

from fastapi_dishka import Middleware, provide_middleware, Provider

class AuthMiddleware(Middleware):
    async def dispatch(self, request, call_next):
        # 💉 Inject services right into your middleware!
        auth_service = await self.get_dependency(request, AuthService)

        if not auth_service.is_authenticated(request):
            return JSONResponse({"error": "Unauthorized"}, status_code=401)

        return await call_next(request)

class SecurityProvider(Provider):
    scope = Scope.APP
    auth_service = provide(AuthService, scope=Scope.APP)

    # 🛡️ Auto-register middleware with DI support
    auth_middleware = provide_middleware(AuthMiddleware)

🏗️ Multiple Providers

Organize your code with multiple providers:

from fastapi_dishka import Provider

# 👤 User-related stuff
class UserProvider(Provider):
    scope = Scope.APP
    user_router = provide_router(user_router)
    user_service = provide(UserService, scope=Scope.APP)

# 📝 Post-related stuff
class PostProvider(Provider):
    scope = Scope.APP
    post_router = provide_router(post_router)
    post_service = provide(PostService, scope=Scope.APP)

# 🚀 Combine them all
app = App("Blog API", "2.0.0", UserProvider(), PostProvider())

🌐 Server Management

Full control over your server lifecycle:

# 🔥 Blocking mode (great for production)
app.start_sync(host="0.0.0.0", port=8080)

# 🧵 Non-blocking mode (perfect for testing)
app.start_sync(blocking=False, port=8081)
# ... do other stuff ...
app.stop()  # 🛑 Graceful shutdown

# ⚡ Async mode
await app.start(host="127.0.0.1", port=8082)

🏗️ Architecture

fastapi-dishka follows a provider-first design:

📦 Your App
├── 🏭 Providers (define what you have)
│   ├── 🛣️  Router providers (auto-register routes)
│   ├── 🛡️  Middleware providers (auto-register middleware)
│   └── 📋 Service providers (your business logic)
├── 🔄 Auto-registration (happens magically)
└── 🚀 FastAPI App (ready to serve)

🎛️ Provider Options

fastapi-dishka gives you flexibility in how you define your providers. You have two options:

Option 1: Use fastapi-dishka Provider (Recommended)

from fastapi_dishka import Provider

class MyProvider(Provider):
    scope = Scope.APP
    # Your provider methods here...

This is the recommended approach as it's specifically designed for fastapi-dishka integration.

Option 2: Use dishka Provider with fastapi-dishka metaclass

from dishka import Provider
from fastapi_dishka import FastAPIDishkaProviderMeta

class MyProvider(Provider, metaclass=FastAPIDishkaProviderMeta):
    scope = Scope.APP
    # Your provider methods here...

This approach allows you to use dishka's Provider directly while still getting fastapi-dishka's auto-registration features through the metaclass.

Both approaches provide the same functionality - choose the one that fits your project's needs! 🎯

🧪 Testing

Testing is a breeze with multiple patterns and full async support! Let's start with the classic hello world test:

import pytest
from fastapi.testclient import TestClient
from dishka import Scope, provide, FromDishka
from fastapi_dishka import App, APIRouter, provide_router, start_test, stop_test, test, Provider

class GreetingService:
    def greet(self, name: str) -> str:
        return f"Hello, {name}! 👋"

hello_router = APIRouter()

@hello_router.get("/hello/{name}")
async def hello_endpoint(name: str, service: FromDishka[GreetingService]) -> dict:
    return {"message": service.greet(name)}

class HelloProvider(Provider):
    scope = Scope.APP
    greeting_router = provide_router(hello_router)
    greeting_service = provide(GreetingService, scope=Scope.APP)

🎯 Pattern 1: Context Manager (Recommended!)

The cleanest and most convenient way to test:

@pytest.mark.asyncio
async def test_hello_world_with_context_manager():
    """The cleanest way to test - using the context manager! 🎯"""
    app = App("Hello World API", "1.0.0", HelloProvider())

    # 🎯 Ultra-clean testing with context manager
    async with test(app) as test_app:
        client = TestClient(test_app.app)
        response = client.get("/hello/World")

        assert response.status_code == 200
        data = response.json()
        assert data["message"] == "Hello, World! 👋"
    # 🧹 Cleanup happens automatically!

🔧 Pattern 2: Manual Start/Stop

For more control over the server lifecycle:

@pytest.mark.asyncio
async def test_hello_world():
    """Manual server management with start_test/stop_test."""
    app = App("Hello World API", "1.0.0", HelloProvider())

    try:
        # 🚀 Use start_test() for clean async server startup
        await start_test(app, port=9999)

        client = TestClient(app.app)
        response = client.get("/hello/World")

        assert response.status_code == 200
        data = response.json()
        assert data["message"] == "Hello, World! 👋"
    finally:
        # 🧹 Use stop_test() for clean async server shutdown
        await stop_test(app)

🎭 Which Pattern to Choose?

  • 🎯 Context Manager: Perfect for most tests, cleanest syntax, automatic cleanup
  • 🔧 Start/Stop: Use when you need custom server lifecycle management or multiple test phases

Both patterns handle provider reuse correctly, so you can use the same providers across multiple tests! 🎉

🤝 Contributing

We love contributions! Here's how to get started:

🚀 Quick Setup

# 📥 Clone the repo
git clone https://github.com/NSXBet/fastapi-dishka.git
cd fastapi-dishka

# 🐍 Create virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# 📦 Install dependencies
pip install -e ".[dev]"

🧪 Running Tests

We maintain 90%+ test coverage (we're a bit obsessed 😅):

# 🏃‍♂️ Run all tests
make test

# 📊 Check coverage
make coverage

# 🔍 Lint your code
make lint

# ✨ Format your code
make format

🎯 Development Standards

  • ✅ Type Safety: We love type hints and use mypy
  • 🧪 Test Coverage: Keep it above 90%
  • 📚 Documentation: Update docs for new features
  • 🎨 Code Style: We use ruff and flake8
  • 🚀 Provider-First: Make providers first-class citizens

💡 Ideas for Contributions

  • 🔌 Additional integrations (SQLAlchemy, Redis, etc.)
  • 📚 More examples and tutorials
  • 🐛 Bug fixes and performance improvements
  • 📖 Documentation improvements
  • 🧪 More test coverage (can we hit 99%? 😏)

🐛 Issues & Questions

Found a bug? Have a question? Want to suggest a feature?

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • 🚀 FastAPI - For making APIs fun again
  • 🍽️ Dishka - For elegant dependency injection
  • ❤️ All our contributors and users

⭐ Show Your Support

If you like this project, please consider giving it a star! It helps others discover fastapi-dishka and motivates us to keep improving it.


Made with ❤️ and lots of ☕

Happy coding! 🚀

Metadata

Release files for fastapi-dishka 0.2.4

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

Source distribution (sdist)

Source distribution for fastapi-dishka 0.2.4
File Size Uploaded
fastapi_dishka-0.2.4.tar.gz 23.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-dishka 0.2.4
File Interpreter ABI Platform
fastapi_dishka-0.2.4-py3-none-any.whl Python 3 none any Details

Total release size: 37.1 kB

Release files / fastapi_dishka-0.2.4.tar.gz

Download URL fastapi_dishka-0.2.4.tar.gz
Size 23.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8db1366d696e535c9af65e3e02001a94d4a165ad2ca4248f1e4e4ab7c0f60640
BLAKE2b-256 checksum
How to use checksums
ca2c3cdca90f32f7ce7c1d462673d9fe4e4e5d603650230c5201790ddbfe80ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 23, 2025.

Transparency log

Release files / fastapi_dishka-0.2.4-py3-none-any.whl

Download URL fastapi_dishka-0.2.4-py3-none-any.whl
Size 13.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
890e1bca725cf29b6db66d488447bf4a39164a6977e23813f5b798553c5e77ff
BLAKE2b-256 checksum
How to use checksums
37d85b686c2f2a3bb75bd329750b305bf4de089f4861d04eed694fdee41dc409
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 23, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.4 This release

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.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