Fastapi Dependency Injection with CLI Arguments
Asked Answered
N

1

0

I want my fastapi routes to include a dependency injection formed from the parameters of a CLI.

In the skeleton code below, a, b and c are the CLI parameters, Consort is the DI and the fastapi class is King.

How can this be achieved?

import charles, william, george #program modules

from fastapi import FastAPI, Depends
       
    app = FastAPI() 
    
    class Consort:
        def __init__(self, a, b, c):
            self.x = a_stuff(a)
            self.y = b_stuff(b)
            self.z = c_stuff(c)
    
    class King:
        def __init__(self, a, b, c):
            ... ...
    
        @router.post("/create")
        async def create(self, consort=Depends(Consort())):
            return charles.create()
    
        @router.post("/read")
        async def read(self, consort=Depends(Consort())):
            return william.read()
    
        @router.post("/update")
        async def update(self, consort=Depends(Consort())):
            return george.update()
    
        @router.post("/delete")
        async def delete(self, consort=Depends(Consort())):
            return elizabeth.delete()
    
    def main(args):
        a, b, c = arg_parse()
        service = King(a, b, c)
        uvicorn.run(... ... ...)
        return
    
    if __name__ == "__main__":
        main(sys.argv)
Nichani answered 14/2, 2023 at 15:4 Comment(5)
What is your question?Delegate
Question is in the preamble ie. How is fastapi initiated with the Consort dependency injection which uses the a, b and c parameters?Nichani
Are you trying to configure a FastAPI app using a CLI?Delegate
The CLI module calls the main (fastapi) module with subprocess.run(["python", "main.py", "-arguments", params], text=True) with params holding the parameters a, b and cNichani
I suggest you re-read FastAPI’s documentation on Depends. It requires a callable (e.g. Consort) not a class instance (e.g. Consort()). Also, you can’t use @router on a class method as explained in #63854313Blandina
G
3

I think what you're after is you want to be able to pass a, b, and c into your constructor, use those to construct a Consort, and then be able to access that Consort instance in your routes. With classy-fastapi I think you can do what you want with something like:

from classy_fastapi import Routable, post
import charles

class Consort:
    def __init__(self, a, b, c):
        self.x = a_stuff(a)
        self.y = b_stuff(b)
        self.z = c_stuff(c)

class King(Routable):
    def __init__(self, consort):
        super().__init__()
        self.consort = consort

    @post("/create")
    async def create(self):
        return charles.create(self.consort)

def main(args):
    a, b, c = arg_parse()
    consort = Consort(a, b, c)
    service = King(consort)
    uvicorn.run(... ... ...)
    return

Note that unlike the Depends way of doing things you do not inject into individual methods. Instead, you inject, via the constructor, into the class that holds the routes.

Full disclosure: I'm the author of classy-fastapi.

Gammer answered 19/2, 2023 at 0:3 Comment(2)
Thanks. 'charles, 'william', etc. are imported modules (question updated). So, for example, I want to pass the DI Consort like charles.create(consort).Nichani
@HenryThornton edited. I think it solves your problem now.Gammer

© 2022 - 2024 — McMap. All rights reserved.