dmontagu / fastapi-utils

Reusable utilities for FastAPI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[QUESTION]

nikhilnimbalkar1 opened this issue · comments

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?