Skip to content

NSXBet/fastapi-dishka

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ 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! πŸš€

About

FastAPI support for Dishka with modules and middleware injection.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors