{"id":41684652,"url":"https://github.com/jymchng/fastapi-service","last_synced_at":"2026-01-24T19:12:57.944Z","repository":{"id":325407146,"uuid":"1099913936","full_name":"jymchng/fastapi-service","owner":"jymchng","description":"Decorate super simple `@injectable` on your FastAPI services.","archived":false,"fork":false,"pushed_at":"2025-11-26T09:39:21.000Z","size":2640,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-29T07:58:12.967Z","etag":null,"topics":["dependency-injection","fastapi","injectable","python"],"latest_commit_sha":null,"homepage":"https://fastapi-service.asyncmove.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jymchng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-19T15:48:59.000Z","updated_at":"2025-11-26T09:39:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jymchng/fastapi-service","commit_stats":null,"previous_names":["jymchng/fastapi-service"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jymchng/fastapi-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Ffastapi-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Ffastapi-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Ffastapi-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Ffastapi-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jymchng","download_url":"https://codeload.github.com/jymchng/fastapi-service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Ffastapi-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28734955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T17:51:25.893Z","status":"ssl_error","status_checked_at":"2026-01-24T17:50:48.377Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","fastapi","injectable","python"],"created_at":"2026-01-24T19:12:57.188Z","updated_at":"2026-01-24T19:12:57.936Z","avatar_url":"https://github.com/jymchng.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cp\u003e\n\u003ca href=\"https://fastapi-service.asyncmove.com\"\u003e\n\u003cimg src=\"https://github.com/jymchng/fastapi-service/raw/main/assets/Fastapi-service-with-name_1-1.png\" width=80% height=20%\u003e\u003c/img\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n\n\u003ci\u003eDecorate super simple \u003cpre\u003e@injectable\u003c/pre\u003e on your FastAPI services.\u003c/i\u003e\n\n\u003chr style=\"border: none; border-top: 1px solid #ccc; margin: 1em 0;\"\u003e\n\n\u003cdiv align=\"left\"\u003e\nDocumentation: \u003ca href=\"https://docs.fastapi-service.asyncmove.com\"\u003e\nhttps://docs.fastapi-service.asyncmove.com\n\u003c/a\u003e\u003cbr\u003e\nSource Code: \u003ca href=\"https://github.com/jymchng/fastapi-service\"\u003e\nhttps://github.com/jymchng/fastapi-service\n\u003c/a\u003e\n\u003c/div\u003e\n\u003chr style=\"border: none; border-top: 1px solid #ccc; margin: 1em 0;\"\u003e\n\n### Compatibility and Version\n\u003cimg src=\"https://img.shields.io/pypi/pyversions/fastapi-service?color=green\" alt=\"Python compat\"\u003e\n\u003ca href=\"https://pypi.python.org/pypi/fastapi-service\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/fastapi-service.svg\" alt=\"PyPi\"\u003e\u003c/a\u003e\n\n### Statistics\n\u003ca href=\"https://github.com/jymchng/fastapi-service/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/jymchng/fastapi-service\" alt=\"Stars\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/network/members\"\u003e\u003cimg src=\"https://img.shields.io/github/forks/jymchng/fastapi-service\" alt=\"Forks\"\u003e\u003c/a\u003e\n\u003ca href=\"https://pypi.python.org/pypi/fastapi-service\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/fastapi-service\" alt=\"Downloads\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/graphs/contributors\"\u003e\u003cimg src=\"https://img.shields.io/github/contributors/jymchng/fastapi-service\" alt=\"Contributors\"\u003e\u003c/a\u003e\n\n### Development and Quality\n\u003ca href=\"https://github.com/jymchng/fastapi-service/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/commit-activity/m/jymchng/fastapi-service\" alt=\"Commits\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/jymchng/fastapi-service\" alt=\"Last Commit\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service\"\u003e\u003cimg src=\"https://img.shields.io/github/languages/code-size/jymchng/fastapi-service\" alt=\"Code Size\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service\"\u003e\u003cimg src=\"https://img.shields.io/github/repo-size/jymchng/fastapi-service\" alt=\"Repo Size\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/watchers\"\u003e\u003cimg src=\"https://img.shields.io/github/watchers/jymchng/fastapi-service\" alt=\"Watchers\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service\"\u003e\u003cimg src=\"https://img.shields.io/github/commit-activity/y/jymchng/fastapi-service\" alt=\"Activity\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/pulls\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr/jymchng/fastapi-service\" alt=\"PRs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/pulls?q=is%3Apr+is%3Aclosed\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr-closed/jymchng/fastapi-service\" alt=\"Merged PRs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/pulls?q=is%3Apr+is%3Aopen\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr/open/jymchng/fastapi-service\" alt=\"Open PRs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/issues?q=is%3Aissue+is%3Aclosed\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-closed/jymchng/fastapi-service\" alt=\"Closed Issues\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/fastapi-service/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/jymchng/fastapi-service\" alt=\"License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/github/jymchng/fastapi-service?branch=main\"\u003e\u003cimg src=\"https://codecov.io/github/jymchng/fastapi-service/coverage.svg?branch=main\" alt=\"Coverage\"\u003e\u003c/a\u003e\n\n\n**Effortless Dependency Injection for FastAPI.**\n\n\u003c/div\u003e\n\n`fastapi-service` is a lightweight, zero-boilerplate dependency injection library designed specifically for FastAPI. It bridges the gap between complex enterprise DI containers and FastAPI's native `Depends` system, making your code cleaner, more testable, and easier to migrate.\n\n## 🚀 Why use this?\n\nFastAPI's dependency injection is powerful, but as your application grows, managing deeply nested dependencies can become verbose. `fastapi-service` solves this by introducing a simple `@injectable` decorator that handles the wiring for you, while staying 100% compatible with standard FastAPI patterns.\n\n### Key Features\n\n  * **Simple APIs**: Just add `@injectable` to your classes. No configuration files, no complex setup.\n  * **Deep FastAPI Integration**: Works directly with `Depends()`. No need to learn a new framework.\n  * **Support for Plain Classes**: Inject classes you didn't write or don't want to decorate (like third-party libraries).\n  * **Gradual Migration**: Adopt it incrementally. Perfect for refactoring legacy codebases without rewriting everything at once.\n\n-----\n\n## 📦 Installation\n\nPIP\n```bash\npip install fastapi-service\n```\n\nUV\n```bash\nuv add fastapi-service\n```\n\nPOETRY\n```bash\npoetry add fastapi-service\n```\n\n-----\n\n## ⚡ Quick Start\n\n### 1\\. Define your services\n\nSimply decorate your classes with `@injectable`. Dependencies defined in `__init__` are automatically resolved.\n\n```python\nfrom fastapi_service import injectable\n\n@injectable\nclass DatabaseService:\n    def get_connection(self):\n        return \"Database Connection\"\n\n@injectable\nclass UserService:\n    # DatabaseService is automatically injected!\n    def __init__(self, db: DatabaseService):\n        self.db = db\n\n    def get_user(self, user_id: int):\n        conn = self.db.get_connection()\n        return {\"id\": user_id, \"name\": \"John Doe\", \"connection\": conn}\n```\n\n### 2\\. Use in FastAPI\n\nUse your services in routes exactly like you would with standard FastAPI dependencies.\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom .services import UserService\n\napp = FastAPI()\n\n@app.get(\"/users/{user_id}\")\ndef read_user(user_id: int, service: UserService = Depends(UserService)):\n    return service.get_user(user_id)\n```\n\n-----\n\n## 🔌 Injecting Plain Objects \u0026 Third-Party Classes\n\nYou don't always have control over the classes you need to use. Whether it's a legacy utility class you can't touch yet, or a client from a third-party library (like `httpx` or `boto3`), `fastapi-service` has you covered.\n\n**You do not need to put `@injectable` on everything.**\n\nIf an `@injectable` service depends on a plain class, the library will automatically attempt to instantiate and inject it for you.\n\n```python\n# --- legacy_utils.py ---\n# This is a plain class. No decorators. \n# Maybe it comes from a library you can't edit!\nclass SimpleLogger:\n    def log(self, message: str):\n        print(f\"[Legacy Log]: {message}\")\n\n# --- services.py ---\nfrom fastapi_service import injectable\nfrom .legacy_utils import SimpleLogger\n\n@injectable\nclass OrderService:\n    # SimpleLogger is NOT decorated, but it is injected automatically.\n    def __init__(self, logger: SimpleLogger):\n        self.logger = logger\n\n    def create_order(self, item: str):\n        self.logger.log(f\"Order created for {item}\")\n```\n\nThis feature is incredibly powerful for integrating:\n\n  * **Third-party clients** (e.g., SDKs that don't use injection).\n  * **Legacy code** during a gradual refactor.\n  * **Data classes** or simple utilities.\n\n-----\n\n## 🔄 Migration Guide (Gradual Adoption)\n\nOne of the biggest strengths of `fastapi-service` is its ability to fit into existing projects without breaking changes. You don't need to convert your entire codebase overnight.\n\n### Step 1: The Legacy Codebase\n\nImagine you have a standard class that isn't using any dependency injection.\n\n```python\n# legacy.py\nclass LegacyEmailSender:\n    def send(self, msg):\n        print(f\"Sending {msg}\")\n```\n\n### Step 2: The Hybrid Approach\n\nYou can write a new service using `@injectable` that depends on the legacy class. Because of the **Plain Object Injection** feature (see above), you don't even need to modify `legacy.py`\\!\n\n```python\nfrom fastapi_service import injectable\nfrom .legacy import LegacyEmailSender\n\n@injectable\nclass NotificationService:\n    # LegacyEmailSender is injected automatically without a decorator\n    def __init__(self, sender: LegacyEmailSender):\n        self.sender = sender \n\n    def notify(self, message: str):\n        self.sender.send(message)\n```\n\n### Step 3: Full Modernization\n\nWhen you are ready, you *can* add `@injectable` to the legacy class if you want it to manage its own dependencies, but it is strictly optional.\n\n-----\n\n## 🧩 Deep Integration with `Depends`\n\n`fastapi-service` is built *on top* of FastAPI's dependency system, not *instead* of it. This means you can mix `@injectable` services with standard FastAPI `Depends` functions.\n\n```python\nfrom fastapi import Header, Depends\nfrom fastapi_service import injectable\n\n# A standard FastAPI dependency function\ndef get_user_agent(user_agent: str = Header(default=None)):\n    return user_agent\n\n@injectable\nclass AnalyticsService:\n    # Injecting a standard FastAPI dependency into a service class!\n    def __init__(self, user_agent: str = Depends(get_user_agent)):\n        self.user_agent = user_agent\n\n    def log_access(self):\n        print(f\"Access from: {self.user_agent}\")\n```\n\n-----\n\n## 🛡️ Scopes \u0026 Scope Safety\n\n`fastapi-service` provides robust scope management to ensure your application's lifecycle is handled correctly. We support two primary scopes:\n\n  * **`Scopes.TRANSIENT` (Default):** A new instance is created for every injection. This is standard FastAPI behavior.\n  * **`Scopes.SINGLETON`:** The same instance is shared across the entire application lifetime.\n\n### Preventing \"Scope Leaks\"\n\nA common pitfall in dependency injection is injecting a short-lived object (Transient) into a long-lived object (Singleton). This causes the short-lived object to \"live forever\" inside the singleton, often leading to stale database sessions or thread-safety issues.\n\n`fastapi-service` **validates your dependency graph at runtime**. When a service is requested, the library checks the entire chain. If you attempt to inject a `TRANSIENT` service into a `SINGLETON` service, it will detect the mismatch and raise an error, preventing unstable behavior.\n\n```python\nfrom fastapi_service import injectable, Scopes\n\n# ❌ ERROR: You cannot inject this Transient service...\n@injectable(scope=Scopes.TRANSIENT)\nclass DatabaseSession:\n    pass\n\n# ...into this Singleton service.\n@injectable(scope=Scopes.SINGLETON)\nclass GlobalCache:\n    def __init__(self, session: DatabaseSession):\n        self.session = session\n```\n\n**Correct Usage:**\nSingletons should only depend on other Singletons or stateless configurations.\n\n```python\n@injectable(scope=Scopes.SINGLETON)\nclass ConnectionPool:\n    pass\n\n@injectable(scope=Scopes.SINGLETON)\nclass UserRepository:\n    def __init__(self, pool: ConnectionPool):\n        self.pool = pool\n```\n\n-----\n\n## 🔧 Under the Hood: Technical Architecture\n\n`fastapi-service` is designed to be a **structural analyzer** that leverages Python's native metaprogramming capabilities to prepare your classes for FastAPI's dependency resolution system.\n\nHere is the step-by-step breakdown of the injection lifecycle:\n\n### 1\\. Introspection \u0026 Registration\n\nWhen you decorate a class with `@injectable`, the library utilizes Python's `inspect` module and `typing.get_type_hints` to analyze the `__init__` constructor. It registers the class and its type hints, preparing them for future resolution.\n\n### 2\\. Dynamic Signature Rewriting (The \"Magic\")\n\nThis is the core mechanism that enables integration with FastAPI. `fastapi-service` dynamically generates a **factory function** for each service.\n\nThe library constructs a new `inspect.Signature` for this factory, programmatically inserting `fastapi.Depends(...)` into the default values of the function parameters.\n\nEssentially, it automates the translation from:\n\n```python\n# Your clean code\nclass UserService:\n    def __init__(self, db: Database): ...\n```\n\nTo the verbose definition FastAPI expects:\n\n```python\n# What FastAPI sees internally\ndef user_service_factory(db: Database = Depends(database_factory)):\n    return UserService(db=db)\n```\n\n### 3\\. Runtime Graph Resolution \u0026 Validation\n\nCurrently, validation occurs dynamically at runtime during the dependency resolution phase.\n\n  * **Scope Safety:** When a dependency is instantiated, the library verifies that no `Scopes.SINGLETON` service is attempting to hold onto a `Scopes.TRANSIENT` service.\n  * **Cycle Detection:** Standard Python recursion limits and dependency resolution mechanics naturally prevent infinite loops.\n\n*Note: Future versions of `fastapi-service` aim to move these validations to build-time (startup) to catch configuration errors even earlier.*\n\n### 4\\. Native Execution Strategy\n\nBecause the library translates your structure into standard FastAPI dependency chains, you retain all the performance benefits of FastAPI's asynchronous execution model. The \"magic\" happens only during the wiring phase; the execution is pure FastAPI.\n\n## 🤝 Contributing\n\nContributions are welcome\\! Please read our contributing guidelines to get started.\n\n## 📄 License\n\nThis project is licensed under the terms of the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjymchng%2Ffastapi-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjymchng%2Ffastapi-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjymchng%2Ffastapi-service/lists"}