fastapi-decorators


Namefastapi-decorators JSON
Version 1.0.13 PyPI version JSON
download
home_pageNone
SummaryCreate decorators for your endpoints using FastAPI dependencies.
upload_time2025-04-07 23:58:50
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT License Copyright (c) 2024 Anders Brams Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords decorators dependencies dependency fastapi middleware
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # FastAPI decorators <!-- omit in toc -->

![CI](https://github.com/Minibrams/fastapi-decorators/actions/workflows/ci.yml/badge.svg)
[![PyPI](https://img.shields.io/pypi/v/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)
[![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)
[![Downloads](https://img.shields.io/pypi/dm/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)

Create decorators with a `@depends()` decorator that leverages FastAPI's `Depends()` and built-in dependencies.

# Installation <!-- omit in toc -->

```bash
uv add fastapi-decorators

# or

pip install fastapi-decorators
```

# TL;DR <!-- omit in toc -->

The library supplies the `depends()` decorator function which converts any function to a decorator that resolves FastAPI dependencies.

Create dependency-enabled decorators simply by using `@depends`:

```python
from fastapi_decorators import depends
from fastapi import Request, Depends, HTTPException

@depends
def authenticate(request: Request, db = Depends(get_db)):
    if db.get_user(request.headers['x-user-id']) is None:
        raise HTTPException(status_code=401, detail="Unauthenticated")

@app.get("/items/{item_id}")
@authenticate
def read_item(item_id: int):
    ...
```

You can use it to make decorator factories like so:

```python
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def authorize(scope: str):
    @depends
    def dependency(token: str = Depends(oauth2_scheme)):
        if scope not in token.scopes:
            raise HTTPException(status_code=403, detail="Unauthorized")

    return dependency

# ... or in the explicit form:
def authorize(scope: str):
    def dependency(token: str = Depends(oauth2_scheme)):
        if scope not in token.scopes:
            raise HTTPException(status_code=403, detail="Unauthorized")

    return depends(dependency)

# Use it:
@app.put("/users/{user_id}")
@authorize("users:write")
def update_user(*, user_id: int, user_update: UserUpdate):
```

It can even be used to overwrite the endpoint logic while _still_ using dependencies:

```python
def cached():
    def decorator(func):
        @depends(cache=Depends(get_cache))    # Dependency `cache` registered here
        @wraps(func)
        def wrapper(*args, cache, **kwargs):  # Dependency `cache` accessible here
            if cache.hit():
                return cache.get()

            result = func(*args, **kwargs)    # Execute the underlying endpoint function as normal

            cache.set(result)
            return result
        return wrapper
    return decorator

@app.get("/very-expensive-operation")
@cached()
def get_a_very_expensive_resource():
    ...
```

# Usage examples

A more detailed version of the documentation is available [here](https://fastapi-decorators.abrams.dk/).

- [Usage examples](#usage-examples)
  - [Using `depends()` directly](#using-depends-directly)
  - [Simple decorator](#simple-decorator)
  - [Decorator factory](#decorator-factory)
  - [Logging decorator](#logging-decorator)
  - [Authorization decorator](#authorization-decorator)
  - [Custom Response Header decorator](#custom-response-header-decorator)
  - [Rate Limiting decorator](#rate-limiting-decorator)
  - [Caching decorator](#caching-decorator)
  - [Error Handling decorator](#error-handling-decorator)
  - [Combining Multiple decorators](#combining-multiple-decorators)
  - [Dependency injection with parameters](#dependency-injection-with-parameters)
  - [Satisfying type checkers](#satisfying-type-checkers)
- [Credits](#credits)

## Using `depends()` directly

If you prefer, you can use depends directly without creating a custom decorator:

```python
from fastapi_decorators import depends
from fastapi import Depends, Header

async def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != "expected-api-key":
        raise HTTPException(status_code=403, detail="Forbidden")

@app.get("/secure-data")
@depends(Depends(verify_api_key))
def get_secure_data():
    ...

```

## Simple decorator

The simplest way to create a decorator is to simply convert a function into a dependency decorator with `@depends`:

```python
from fastapi_decorators import depends
from fastapi import Request, Depends

@depends
def audit_request(request: Request, db: Session = Depends(get_db)):
    log = AuditLog(request.host.ip, request.url.path)
    db.add(log)
    db.commit()

@app.get('/users/')
@audit_request
def get_users():
    ...
```

If preferred, the non-decorator syntax can also be used:

```python
from fastapi_decorators import depends
from fastapi import Request, Depends


def audit_request():
    def dependency(request: Request, db: Session = Depends(get_db)):
        log = AuditLog(request.host.ip, request.url.path)
        db.add(log)
        db.commit()

    return depends(dependency)

@app.get('/users/')
@audit_request()
def get_users():
    ...
```

## Decorator factory

In some cases, you need to provide variations of the same dependency.
To do this, create a decorator factory:

```python
def require_headers(*headers: str):
    def dependency(request: Request):
        if not all(header in request.headers for header in headers):
            raise HTTPException(status=400, detail="Required headers not provided.")

    return depends(dependency)


@app.put("/users/{user_id}")
@require_headers("X-API-KEY", "X-TENANT-ID")
def update_user(*, user_id: int, user_update: UserUpdate):
    ...
```

## Logging decorator

Add a decorator to log incoming requests:

```python
from fastapi_decorators import depends
from fastapi import Request

@depends
def log_request(request: Request):
    print(f"Received request: {request.method} {request.url}")

@app.get("/items/{item_id}")
@log_request
def read_item(item_id: int):
    ...

```

## Authorization decorator

Create a simple decorator that rejects unauthorized requests:

> The API docs will reflect the authentication requirement for this endpoint
> because of the added OAuth2 dependency.

```python
from fastapi_decorators import depends
from fastapi import Depends, HTTPException, Header
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token", auto_error=False)

def authorize(*scopes: str):
    def dependency(token: str | None = Depends(oauth2_scheme)):
        if not token:
            raise HTTPException(status_code=401, detail="Unauthenticated")

        if not all(scope in token.scopes for scope in scopes):
            raise HTTPException(status_code=403, detail="Unauthorized")

    return depends(dependency)


@app.put("/users/{user_id}")
@authorize("users:read", "users:write")
def update_user(*, user_id: int, user_update: UserUpdate):
    ...

```

## Custom Response Header decorator

Create a decorator to add custom headers to responses:

```python
from fastapi_decorators import depends
from fastapi import Response, Depends

def add_custom_header(name: str, value: str):
    def dependency(response: Response):
        response.headers[name] = value
    return depends(dependency)

@app.get("/data")
@add_custom_header("X-Custom-Header", "MyValue")
def get_data():
    ...

```

## Rate Limiting decorator

Add rate limiting to your endpoints:

```python
from fastapi_decorators import depends
from fastapi import Depends, HTTPException, Request
from time import time

rate_limit_store = {}

def rate_limit(max_calls: int, period: int):
    def dependency(ip_address: str = Depends(get_ip_address)):
        # Simple rate limiting logic
        now = time()
        calls, last_reset = rate_limit_store.get(ip_address, (0, now))
        if now - last_reset > period:
            # Reset rate limit
            calls = 0
            last_reset = now
        if calls >= max_calls:
            raise HTTPException(status_code=429, detail="Too Many Requests")
        calls += 1
        rate_limit_store[ip_address] = (calls, last_reset)
    return depends(dependency)

def get_ip_address(request: Request):
    return request.client.host

@app.get("/limited-endpoint")
@rate_limit(max_calls=5, period=60)
def limited_endpoint():
    ...

```

## Caching decorator

Add caching to your endpoints:

```python
cache_storage = {}

def get_cache() -> dict:
    return cache_storage  # Use a real cache like Redis or Memcached

def cache_response(max_age: int = 5):
    def decorator(func):

        # Wrap the endpoint after adding the get_cache dependency
        @depends(cache=Depends(get_cache)) # The `cache` dependency is defined here
        @wraps(func)
        def wrapper(*args, cache: dict, **kwargs): # The `cache` dependency can be accessed here
            key = func.__name__

            if key in cache:
                timestamp, data = cache[key]
                if time() - timestamp < max_age:
                    # Cache hit
                    return data

            # Cache miss - call the endpoint as usual
            result = func(*args, **kwargs)

            # Store the result in the cache
            cache[key] = time(), result
            return result

        return wrapper
    return decorator

@app.get("/cached-data")
@cache_response(max_age=10)
def get_cached_data():
    ...
```

1. We add the `get_cache` dependency with a keyword argument so we can access it in the wrapper function later.
2. Because we added the `get_cache` dependency with the keyword argument `cache`, we can access it in here. This also works for normal endpoints.

## Error Handling decorator

Create a decorator to handle exceptions and return custom responses:

```python
from fastapi_decorators import depends
from fastapi import Depends, Response

crash_logs = []

def get_crash_log_storage() -> list:
    return crash_logs  # Use a real storage like a database

def handle_errors():
    def decorator(func):

        # Wrap the endpoint after adding the crash_logs dependency
        @depends(crash_logs = Depends(get_crash_log_storage))
        @wraps(func)
        def wrapper(*args, crash_logs: list, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                # Log the error and return a custom response
                crash_logs.append({ 'error': str(e), 'function': func.__name__ })
                return JSONResponse(status_code=500, content={ "detail": str(e) })

        return wrapper
    return decorator

@app.get("/may-fail")
@handle_errors()
def may_fail_operation():
    ...

```

## Combining Multiple decorators

You can combine multiple decorators to compose complex behavior:

```python
@app.post("/submit")
@log_request()
@add_custom_header("X-Processed-By", "FastAPI")
@handle_errors()
def submit_data(data: DataModel):
    ...

```

## Dependency injection with parameters

You can pass parameters to your dependencies through closures:

```python
from fastapi_decorators import depends
from fastapi import Depends, HTTPException

def verify_role(required_role: str):
    def dependency(current_user: User = Depends(get_current_user)):
        if current_user.role != required_role:
            raise HTTPException(status_code=403, detail="Forbidden")
    return dependency

@app.get("/admin-area")
@depends(verify_role("admin"))
def admin_area():
    ...

```

## Satisfying type checkers

If you're using a type checker like Mypy with a `strict` configuration, the library exposes two useful types `Decorator` and `F` for satisfying type checks on decorators and their decorated functions:

```python
from fastapi_decorators import depends
from fastapi_decorators.types import Decorator, F

def authorize() -> Decorator:
    async def dependency(...) -> None:
        ...

    return depends(dependency)

def cache_response(...) -> Decorator:
    def decorator(func: F) -> F:

        @depends(cache=Depends(get_cache))
        @wraps(func)
        def wrapper(...) -> Any:
            ...

        return wrapper
    return decorator
```

# Credits

Inspired by solutions suggested by [@gocreating](https://github.com/gocreating) and [@dmontagu](https://github.com/dmontagu).

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "fastapi-decorators",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "decorators, dependencies, dependency, fastapi, middleware",
    "author": null,
    "author_email": "Anders Brams <anders@brams.dk>",
    "download_url": "https://files.pythonhosted.org/packages/6e/dd/ee33937ee4840b855581e3ab3b5115e9648817cac8352f6242490a534360/fastapi_decorators-1.0.13.tar.gz",
    "platform": null,
    "description": "# FastAPI decorators <!-- omit in toc -->\n\n![CI](https://github.com/Minibrams/fastapi-decorators/actions/workflows/ci.yml/badge.svg)\n[![PyPI](https://img.shields.io/pypi/v/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)\n[![Downloads](https://img.shields.io/pypi/dm/fastapi-decorators.svg)](https://pypi.org/project/fastapi-decorators/)\n\nCreate decorators with a `@depends()` decorator that leverages FastAPI's `Depends()` and built-in dependencies.\n\n# Installation <!-- omit in toc -->\n\n```bash\nuv add fastapi-decorators\n\n# or\n\npip install fastapi-decorators\n```\n\n# TL;DR <!-- omit in toc -->\n\nThe library supplies the `depends()` decorator function which converts any function to a decorator that resolves FastAPI dependencies.\n\nCreate dependency-enabled decorators simply by using `@depends`:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Request, Depends, HTTPException\n\n@depends\ndef authenticate(request: Request, db = Depends(get_db)):\n    if db.get_user(request.headers['x-user-id']) is None:\n        raise HTTPException(status_code=401, detail=\"Unauthenticated\")\n\n@app.get(\"/items/{item_id}\")\n@authenticate\ndef read_item(item_id: int):\n    ...\n```\n\nYou can use it to make decorator factories like so:\n\n```python\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\ndef authorize(scope: str):\n    @depends\n    def dependency(token: str = Depends(oauth2_scheme)):\n        if scope not in token.scopes:\n            raise HTTPException(status_code=403, detail=\"Unauthorized\")\n\n    return dependency\n\n# ... or in the explicit form:\ndef authorize(scope: str):\n    def dependency(token: str = Depends(oauth2_scheme)):\n        if scope not in token.scopes:\n            raise HTTPException(status_code=403, detail=\"Unauthorized\")\n\n    return depends(dependency)\n\n# Use it:\n@app.put(\"/users/{user_id}\")\n@authorize(\"users:write\")\ndef update_user(*, user_id: int, user_update: UserUpdate):\n```\n\nIt can even be used to overwrite the endpoint logic while _still_ using dependencies:\n\n```python\ndef cached():\n    def decorator(func):\n        @depends(cache=Depends(get_cache))    # Dependency `cache` registered here\n        @wraps(func)\n        def wrapper(*args, cache, **kwargs):  # Dependency `cache` accessible here\n            if cache.hit():\n                return cache.get()\n\n            result = func(*args, **kwargs)    # Execute the underlying endpoint function as normal\n\n            cache.set(result)\n            return result\n        return wrapper\n    return decorator\n\n@app.get(\"/very-expensive-operation\")\n@cached()\ndef get_a_very_expensive_resource():\n    ...\n```\n\n# Usage examples\n\nA more detailed version of the documentation is available [here](https://fastapi-decorators.abrams.dk/).\n\n- [Usage examples](#usage-examples)\n  - [Using `depends()` directly](#using-depends-directly)\n  - [Simple decorator](#simple-decorator)\n  - [Decorator factory](#decorator-factory)\n  - [Logging decorator](#logging-decorator)\n  - [Authorization decorator](#authorization-decorator)\n  - [Custom Response Header decorator](#custom-response-header-decorator)\n  - [Rate Limiting decorator](#rate-limiting-decorator)\n  - [Caching decorator](#caching-decorator)\n  - [Error Handling decorator](#error-handling-decorator)\n  - [Combining Multiple decorators](#combining-multiple-decorators)\n  - [Dependency injection with parameters](#dependency-injection-with-parameters)\n  - [Satisfying type checkers](#satisfying-type-checkers)\n- [Credits](#credits)\n\n## Using `depends()` directly\n\nIf you prefer, you can use depends directly without creating a custom decorator:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Depends, Header\n\nasync def verify_api_key(x_api_key: str = Header(...)):\n    if x_api_key != \"expected-api-key\":\n        raise HTTPException(status_code=403, detail=\"Forbidden\")\n\n@app.get(\"/secure-data\")\n@depends(Depends(verify_api_key))\ndef get_secure_data():\n    ...\n\n```\n\n## Simple decorator\n\nThe simplest way to create a decorator is to simply convert a function into a dependency decorator with `@depends`:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Request, Depends\n\n@depends\ndef audit_request(request: Request, db: Session = Depends(get_db)):\n    log = AuditLog(request.host.ip, request.url.path)\n    db.add(log)\n    db.commit()\n\n@app.get('/users/')\n@audit_request\ndef get_users():\n    ...\n```\n\nIf preferred, the non-decorator syntax can also be used:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Request, Depends\n\n\ndef audit_request():\n    def dependency(request: Request, db: Session = Depends(get_db)):\n        log = AuditLog(request.host.ip, request.url.path)\n        db.add(log)\n        db.commit()\n\n    return depends(dependency)\n\n@app.get('/users/')\n@audit_request()\ndef get_users():\n    ...\n```\n\n## Decorator factory\n\nIn some cases, you need to provide variations of the same dependency.\nTo do this, create a decorator factory:\n\n```python\ndef require_headers(*headers: str):\n    def dependency(request: Request):\n        if not all(header in request.headers for header in headers):\n            raise HTTPException(status=400, detail=\"Required headers not provided.\")\n\n    return depends(dependency)\n\n\n@app.put(\"/users/{user_id}\")\n@require_headers(\"X-API-KEY\", \"X-TENANT-ID\")\ndef update_user(*, user_id: int, user_update: UserUpdate):\n    ...\n```\n\n## Logging decorator\n\nAdd a decorator to log incoming requests:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Request\n\n@depends\ndef log_request(request: Request):\n    print(f\"Received request: {request.method} {request.url}\")\n\n@app.get(\"/items/{item_id}\")\n@log_request\ndef read_item(item_id: int):\n    ...\n\n```\n\n## Authorization decorator\n\nCreate a simple decorator that rejects unauthorized requests:\n\n> The API docs will reflect the authentication requirement for this endpoint\n> because of the added OAuth2 dependency.\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Depends, HTTPException, Header\nfrom fastapi.security import OAuth2PasswordBearer\nfrom sqlalchemy.orm import Session\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\", auto_error=False)\n\ndef authorize(*scopes: str):\n    def dependency(token: str | None = Depends(oauth2_scheme)):\n        if not token:\n            raise HTTPException(status_code=401, detail=\"Unauthenticated\")\n\n        if not all(scope in token.scopes for scope in scopes):\n            raise HTTPException(status_code=403, detail=\"Unauthorized\")\n\n    return depends(dependency)\n\n\n@app.put(\"/users/{user_id}\")\n@authorize(\"users:read\", \"users:write\")\ndef update_user(*, user_id: int, user_update: UserUpdate):\n    ...\n\n```\n\n## Custom Response Header decorator\n\nCreate a decorator to add custom headers to responses:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Response, Depends\n\ndef add_custom_header(name: str, value: str):\n    def dependency(response: Response):\n        response.headers[name] = value\n    return depends(dependency)\n\n@app.get(\"/data\")\n@add_custom_header(\"X-Custom-Header\", \"MyValue\")\ndef get_data():\n    ...\n\n```\n\n## Rate Limiting decorator\n\nAdd rate limiting to your endpoints:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Depends, HTTPException, Request\nfrom time import time\n\nrate_limit_store = {}\n\ndef rate_limit(max_calls: int, period: int):\n    def dependency(ip_address: str = Depends(get_ip_address)):\n        # Simple rate limiting logic\n        now = time()\n        calls, last_reset = rate_limit_store.get(ip_address, (0, now))\n        if now - last_reset > period:\n            # Reset rate limit\n            calls = 0\n            last_reset = now\n        if calls >= max_calls:\n            raise HTTPException(status_code=429, detail=\"Too Many Requests\")\n        calls += 1\n        rate_limit_store[ip_address] = (calls, last_reset)\n    return depends(dependency)\n\ndef get_ip_address(request: Request):\n    return request.client.host\n\n@app.get(\"/limited-endpoint\")\n@rate_limit(max_calls=5, period=60)\ndef limited_endpoint():\n    ...\n\n```\n\n## Caching decorator\n\nAdd caching to your endpoints:\n\n```python\ncache_storage = {}\n\ndef get_cache() -> dict:\n    return cache_storage  # Use a real cache like Redis or Memcached\n\ndef cache_response(max_age: int = 5):\n    def decorator(func):\n\n        # Wrap the endpoint after adding the get_cache dependency\n        @depends(cache=Depends(get_cache)) # The `cache` dependency is defined here\n        @wraps(func)\n        def wrapper(*args, cache: dict, **kwargs): # The `cache` dependency can be accessed here\n            key = func.__name__\n\n            if key in cache:\n                timestamp, data = cache[key]\n                if time() - timestamp < max_age:\n                    # Cache hit\n                    return data\n\n            # Cache miss - call the endpoint as usual\n            result = func(*args, **kwargs)\n\n            # Store the result in the cache\n            cache[key] = time(), result\n            return result\n\n        return wrapper\n    return decorator\n\n@app.get(\"/cached-data\")\n@cache_response(max_age=10)\ndef get_cached_data():\n    ...\n```\n\n1. We add the `get_cache` dependency with a keyword argument so we can access it in the wrapper function later.\n2. Because we added the `get_cache` dependency with the keyword argument `cache`, we can access it in here. This also works for normal endpoints.\n\n## Error Handling decorator\n\nCreate a decorator to handle exceptions and return custom responses:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Depends, Response\n\ncrash_logs = []\n\ndef get_crash_log_storage() -> list:\n    return crash_logs  # Use a real storage like a database\n\ndef handle_errors():\n    def decorator(func):\n\n        # Wrap the endpoint after adding the crash_logs dependency\n        @depends(crash_logs = Depends(get_crash_log_storage))\n        @wraps(func)\n        def wrapper(*args, crash_logs: list, **kwargs):\n            try:\n                return func(*args, **kwargs)\n            except Exception as e:\n                # Log the error and return a custom response\n                crash_logs.append({ 'error': str(e), 'function': func.__name__ })\n                return JSONResponse(status_code=500, content={ \"detail\": str(e) })\n\n        return wrapper\n    return decorator\n\n@app.get(\"/may-fail\")\n@handle_errors()\ndef may_fail_operation():\n    ...\n\n```\n\n## Combining Multiple decorators\n\nYou can combine multiple decorators to compose complex behavior:\n\n```python\n@app.post(\"/submit\")\n@log_request()\n@add_custom_header(\"X-Processed-By\", \"FastAPI\")\n@handle_errors()\ndef submit_data(data: DataModel):\n    ...\n\n```\n\n## Dependency injection with parameters\n\nYou can pass parameters to your dependencies through closures:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi import Depends, HTTPException\n\ndef verify_role(required_role: str):\n    def dependency(current_user: User = Depends(get_current_user)):\n        if current_user.role != required_role:\n            raise HTTPException(status_code=403, detail=\"Forbidden\")\n    return dependency\n\n@app.get(\"/admin-area\")\n@depends(verify_role(\"admin\"))\ndef admin_area():\n    ...\n\n```\n\n## Satisfying type checkers\n\nIf you're using a type checker like Mypy with a `strict` configuration, the library exposes two useful types `Decorator` and `F` for satisfying type checks on decorators and their decorated functions:\n\n```python\nfrom fastapi_decorators import depends\nfrom fastapi_decorators.types import Decorator, F\n\ndef authorize() -> Decorator:\n    async def dependency(...) -> None:\n        ...\n\n    return depends(dependency)\n\ndef cache_response(...) -> Decorator:\n    def decorator(func: F) -> F:\n\n        @depends(cache=Depends(get_cache))\n        @wraps(func)\n        def wrapper(...) -> Any:\n            ...\n\n        return wrapper\n    return decorator\n```\n\n# Credits\n\nInspired by solutions suggested by [@gocreating](https://github.com/gocreating) and [@dmontagu](https://github.com/dmontagu).\n",
    "bugtrack_url": null,
    "license": "MIT License\n        \n        Copyright (c) 2024 Anders Brams\n        \n        Permission is hereby granted, free of charge, to any person obtaining a copy\n        of this software and associated documentation files (the \"Software\"), to deal\n        in the Software without restriction, including without limitation the rights\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n        copies of the Software, and to permit persons to whom the Software is\n        furnished to do so, subject to the following conditions:\n        \n        The above copyright notice and this permission notice shall be included in all\n        copies or substantial portions of the Software.\n        \n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n        SOFTWARE.",
    "summary": "Create decorators for your endpoints using FastAPI dependencies.",
    "version": "1.0.13",
    "project_urls": {
        "Documentation": "https://github.com/Minibrams/fastapi-decorators",
        "Homepage": "https://github.com/Minibrams/fastapi-decorators",
        "Issues": "https://github.com/Minibrams/fastapi-decorators/issues",
        "Repository": "https://github.com/Minibrams/fastapi-decorators"
    },
    "split_keywords": [
        "decorators",
        " dependencies",
        " dependency",
        " fastapi",
        " middleware"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6eddee33937ee4840b855581e3ab3b5115e9648817cac8352f6242490a534360",
                "md5": "9f6ba5ae313ca2bcd7ff51b6e5905f48",
                "sha256": "d3b722486f15ffbd1a21ef9e71775fde9e38448d30246d7de7b7cf99a0509d70"
            },
            "downloads": -1,
            "filename": "fastapi_decorators-1.0.13.tar.gz",
            "has_sig": false,
            "md5_digest": "9f6ba5ae313ca2bcd7ff51b6e5905f48",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 8389,
            "upload_time": "2025-04-07T23:58:50",
            "upload_time_iso_8601": "2025-04-07T23:58:50.269547Z",
            "url": "https://files.pythonhosted.org/packages/6e/dd/ee33937ee4840b855581e3ab3b5115e9648817cac8352f6242490a534360/fastapi_decorators-1.0.13.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-04-07 23:58:50",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Minibrams",
    "github_project": "fastapi-decorators",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "fastapi-decorators"
}
        
Elapsed time: 1.07922s