Skip to main content

Starlette DI

Supported Python versions Package version Supported Starlette versions Publish Coverage Status License

Starlette DI is a dependency injection library for Starlette applications. It simplifies dependency management by allowing services to be injected using Scoped, Transient, and Singleton lifetimes (similar to .NET Core). Also, enables automatic injection of route parameters, and request bodies using Pydantic models, making API development more efficient, and structured.

Table of Contents

Features

  • Scoped, Transient, and Singleton: Dependency injection with three service lifetimes, similar to .NET Core.
  • Service Injection: Supports injecting services into functions, methods, and endpoint classes in Starlette.
  • Route Parameter Injection: Automatically extracts URL parameters in controllers.
  • Request Body Injection: Maps JSON request body data directly to Pydantic models.
  • Dependency Injection Middleware: Provides a middleware layer to manage dependency injection throughout the request lifecycle.
  • Pydantic Compatibility: Leverages Pydantic for data validation, and conversion.
  • Decorators for Endpoints: Simplifies injection with @inject, @inject_method, and @inject_class.

Requirements

  • Python>=3.10
  • Starlette>=0.38.0
  • Pydantic>=1.10.21

Installation

You can simply install starlette-di from PyPI:

pip install starlette-di

Tutorial

1. Create a service

Define a service that can be injected:

from abc import ABC, abstractmethod

class IGreeter(ABC):
    @abstractmethod
    def greet(self) -> str: ...


class Greeter(IGreeter):
    def greet(self) -> str:
        return 'Hello!'

Alternatively, use a factory function:

def greeter_factory() -> IGreeter:
    return Greeter()

2. Configure dependency injection

Use a ServiceCollection to register services with different lifetimes:

  • Singleton: one instance for the application lifetime.
  • Scoped: one instance per request.
  • Transient: new instance created each time it's requested.

Example:

from starlette_di import ServiceCollection

services = ServiceCollection()
services.add_transient(IGreeter, Greeter)
# also, services.add_scoped(IGreeter, Greeter)
# or services.add_singleton(IGreeter, Greeter)
provider = services.build_provider()

Using a factory function:

def greeter_factory() -> IGreeter:
    return Greeter()

services.add_transient(IGreeter, greeter_factory)

3. Injecting services

Use the @inject, @inject_method, and @inject_class decorators to inject the service into an endpoint function, method or class respectively.

Inject into an endpoint function

Inject the service into an endpoint function using the @inject decorator:

from starlette.requests import Request
from starlette.responses import JSONResponse

from starlette_di import inject

@inject
async def greet(request: Request, greeter: IGreeter):
    return JSONResponse({'message': greeter.greet()})

Inject into an endpoint method

Inject the service into an endpoint method using the @inject_method decorator:

from starlette.requests import Request
from starlette.endpoints import HTTPEndpoint
from starlette.responses import JSONResponse

from starlette_di import inject_method

class GreetEndpoint(HTTPEndpoint):
    @inject_method
    async def get(self, request: Request, greeter: IGreeter):
        return JSONResponse({'message': greeter.greet()})

Inject into an endpoint class

Inject the service into an endpoint class using the @inject_class decorator:

from starlette.responses import JSONResponse
from starlette.endpoints import HTTPEndpoint

from starlette_di import inject_class

@inject_class
class GreetEndpoint(HTTPEndpoint):
    def __init__(self, request: Request, greeter: IGreeter):
        super().__init__(request)
        self.greeter = greeter

    async def get(self, request: Request):
        return JSONResponse({'message': self.greeter.greet()})

4. Inject path params

You can inject request path parameters:

from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route

from starlette_di import inject

@inject
async def greet_person(self, request: Request, name: str):
    return JSONResponse({'message': f'Hello {name}!'})

routes = [
    Route('/greet/{name:str}', greet_person),
]

5. Inject request body

Also, you can inject the request body using Pydantic models. If there's only one Pydantic model parameter, the whole JSON body is injected. Otherwise, each parameter is extracted from the JSON body using its name.

Only one parameter:

from pydantic import BaseModel
from starlette.requests import Request
from starlette.responses import JSONResponse

class User(BaseModel):
    name: str
    age: int

@inject
async def create_user(request: Request, user: User):
    return JSONResponse({'name': user.name, 'age': user.age})

# Example request
# {'name': 'Jane Doe', 'age': 25}

Two or more parameters

from pydantic import BaseModel
from starlette.requests import Request
from starlette.responses import JSONResponse

class User(BaseModel):
    name: str
    age: int

class Product(BaseModel):
    name: str
    price: float

@inject
async def update_product(request: Request, user: User, product: Product):
    return JSONResponse({'user_name': user.name, 'product_name': product.name})

# Example request
# {
#     'user': {'name': 'Jane Doe', 'age': 25},
#     'product': {'name': 'Computer', 'price': 225.0},
# }

6. Use the DependencyInjectionMiddleware

Use the DependencyInjectionMiddleware to handle dependency injection.

This middleware sets up the request scope for dependency injection by creating a scoped service provider, and adding it to the request scope.

Pass the service provider built in here to the service_provider argument of the middleware:

from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.routing import Route
from starlette_di import DependencyInjectionMiddleware

app = Starlette(
    routes=[Route('/greet', GreetEndpoint)],
    middleware=[
        Middleware(DependencyInjectionMiddleware, service_provider=provider),
    ]
)

Full example

Find the full tutorial example here.

Contributing

See the contribution guidelines.

License

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

Support

If you find this project useful, give it a ⭐ on GitHub!

Metadata

Release files for starlette-di 0.1.1

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

Source distribution (sdist)

Source distribution for starlette-di 0.1.1
File Size Uploaded Provenance Actions
starlette_di-0.1.1.tar.gz 16.0 kB With provenance Details for starlette_di-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for starlette-di 0.1.1
File Interpreter ABI Platform Actions
starlette_di-0.1.1-py3-none-any.whl Python 3 none any Details for starlette_di-0.1.1-py3-none-any.whl

Total release size: 30.1 kB

Release files / starlette_di-0.1.1.tar.gz

Download URL starlette_di-0.1.1.tar.gz
Size 16.0 kB
Tags Source
SHA-256 checksum
How to use checksums
2f73be0de3658acd8e87e191769a9183f331d92f482a4766c4e8bd9233df0fcf
BLAKE2b-256 checksum
How to use checksums
0f2ecaf7638e90f4797039225b27f86f75a9a4d5231566fcaf89787601cbde12
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 Mar 14, 2025.

Transparency log

Release files / starlette_di-0.1.1-py3-none-any.whl

Download URL starlette_di-0.1.1-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ebc64997bfabf9c1c84b8bcce5bcdcb6d3a32189f4f6a3f65f63e4b38ad3f692
BLAKE2b-256 checksum
How to use checksums
569c5b1ccc2522f80a668c3e769771b6fbb722b45d86f4a493197a63676f285a
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 Mar 14, 2025.

Transparency log

Security for starlette-di 0.1.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for starlette_di-0.1.1.tar.gz

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 Mar 14, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

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