pythondependenciesfastapidecorator

FastAPI dynamic advanced dependencies /


I started from the example shown on this page : https://fastapi.tiangolo.com/advanced/advanced-dependencies/#use-the-instance-as-a-dependency

from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()

class FixedContentQueryChecker:
    def __init__(self, fixed_content: str):
        self.fixed_content = fixed_content

    def __call__(self, q: str = ""):
        if q:
            return self.fixed_content in q
        return False

checker = FixedContentQueryChecker("bar")

@app.get("/query-checker/")
async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]):
    return {"fixed_content_in_query": fixed_content_included}

Now, I would like to be able to use the same kind of dependency injection but with a dynamically defined value, using a decorator.

def config_checker(value):
    checker = FixedContentQueryChecker(value)
    def f(func):
        @functools.wraps(func)
        async def wrap_func(*args, fixed_content_included: Annotated[bool, Depends(checker)], **kwargs):
            return await func(*args, fixed_content_included, **kwargs)
    return wrap_func
return f

@app.get("/query-bar-checker/")
@config_checker(value="bar")
async def read_query_check_bar(fixed_content_included: Annotated[bool, Depends(??)]):
    return {"fixed_content_in_query": fixed_content_included}

@app.get("/query-foo-checker/")
@config_checker(value="foo")
async def read_query_check_foo(fixed_content_included: Annotated[bool, Depends(??)]):
    return {"fixed_content_in_query": fixed_content_included}

The problem is I need to define the fixed_content_included as a dependency in the routes so that it won't be treated as a query parameter. But if I provide anything in the Depends() function in the route definition, it won't be able to be overridden by the decorator so that the parametrized function would be used.

How can I proceed ?


Solution

  • I eventually found a solution using the fastapi-decorators library.

    Here's what I achieved to do so far :

    import functools
    from fastapi import Depends, FastAPI
    from fastapi_decorators import depends
    
    app = FastAPI()
    
    def config_checker(value):
        def f(func):
            def checker():
                return value
    
            @depends(fixed_content_included=Depends(checker))
            @functools.wraps(func)
            async def wrap_func(*args, fixed_content_included, **kwargs):
                return await func(*args, fixed_content_included=fixed_content_included, **kwargs)
            return wrap_func
        return f
    
    @app.get("/")
    @config_checker(value="foobar")
    async def read_query_check_bar(fixed_content_included):
        return {"fixed_content_in_query": fixed_content_included}
    
    @app.get("/two")
    @config_checker(value="quux")
    async def read_query_check_bar(fixed_content_included):
        return {"fixed_content_in_query": fixed_content_included}
    

    I still need to check if it can still fit more complex needs but I think it answers what I was asking for here.