dmontagu / fastapi-utils

Reusable utilities for FastAPI
MIT License
1.89k stars 165 forks source link

[QUESTION] #262

Open nikhilnimbalkar1 opened 1 year ago

nikhilnimbalkar1 commented 1 year ago

Trying to create generic CRUD class for all endpoints

I am fairly new to FastAPI(migrating from Django) and I am trying to create a generic CRUD operations class that I can inherit and use across my CBV endpoints. Something like this :

class AbstractCrud
      model: Base = NotImplemented
      session: Session = NotImplemented

      def get_items(self, limit,  **filters):
          """ Read operation """

      def get_item(self, pk: int):

      def create_item(self, obj: BaseModel):
          """ Create operation """

      def update_item(self, pk: int, **params):
          """ Update operation"""

      def delete_item(self, pk: int):
        """ Delete operation """

router = InferringRouter()

@cbv(router)
class UserAPI(AbstractCrud):
    router.tags = ["User"]
    router.prefix = "/users"

    model = User
    session: Session = Depends(get_db)

   # my endpoints
   #e.g. @router.get(...)

@cbv(router)
class PostAPI(AbstractCrud):
    router.tags = ["Post"]
    router.prefix = "/posts"

    model = Post
    session: Session = Depends(get_db)

    # my endpoints
    #e.g. @router.get(...)

I get the following error if I try to do the above: fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'sqlalchemy.orm.decl_api.Base'> is a valid pydantic field type For now, I am able to achieve this as follows:

class AbstractCrud
      model: Base = NotImplemented
      session: Session = NotImplemented

      def get_items(self, limit,  **filters):
          """ Read operation """

      def get_item(self, pk: int):

      def create_item(self, obj: BaseModel):
          """ Create operation """

      def update_item(self, pk: int, **params):
          """ Update operation"""

      def delete_item(self, pk: int):
        """ Delete operation """

class UserCrud(AbstractCrud):

    def __init__(self, session: Session):
        self.session = session
        self.model = User

class PostCrud(AbstractCrud):

    def __init__(self, session: Session):
        self.session = session
        self.model = Post

router = InferringRouter()

@cbv(router)
class UserAPI:
    router.tags = ["User"]
    router.prefix = "/users"

    def __init__(self, session=Depends(get_db)):
        self.session = session
        self.crud = UserCrud(self.session)

   # my endpoints
   #e.g. @router.get(...)

@cbv(router)
class PostAPI:
    router.tags = ["Post"]
    router.prefix = "/posts"

    def __init__(self, session=Depends(get_db)):
        self.session = session
        self.crud = PostCrud(self.session)

    # my endpoints
    #e.g. @router.get(...)

Although this is working fine for me now, I can't help but think if there is a better(or correct) way to do this.

Also, Is my use of a single router variable across multiple classes correct?