Skip to content

Controllers

API controllers and route handlers for the FastAPI Boilerplate.

Base Controller

Controller Structure

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List, Optional

from app.core.database import get_db
from app.schemas import BaseSchema
from app.services import BaseService

class BaseController:
    def __init__(self, service: BaseService):
        self.service = service
        self.router = APIRouter()
        self._register_routes()

    def _register_routes(self):
        raise NotImplementedError("Subclasses must implement _register_routes")

User Controller

User Routes

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List

from app.core.database import get_db
from app.core.auth import get_current_user
from app.schemas.user import UserCreate, UserUpdate, UserResponse
from app.services.user import UserService
from app.models.user import User

class UserController(BaseController):
    def __init__(self, service: UserService):
        super().__init__(service)

    def _register_routes(self):
        self.router.post("/", response_model=UserResponse)(self.create)
        self.router.get("/me", response_model=UserResponse)(self.get_me)
        self.router.get("/{user_id}", response_model=UserResponse)(self.get)
        self.router.put("/{user_id}", response_model=UserResponse)(self.update)
        self.router.delete("/{user_id}")(self.delete)

    async def create(self, user: UserCreate, db: Session = Depends(get_db)):
        return await self.service.create(db, user)

    async def get_me(self, current_user: User = Depends(get_current_user)):
        return current_user

    async def get(self, user_id: int, db: Session = Depends(get_db)):
        return await self.service.get(db, user_id)

    async def update(
        self,
        user_id: int,
        user: UserUpdate,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
    ):
        if current_user.id != user_id and not current_user.is_superuser:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions"
            )
        return await self.service.update(db, user_id, user)

    async def delete(
        self,
        user_id: int,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
    ):
        if current_user.id != user_id and not current_user.is_superuser:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions"
            )
        return await self.service.delete(db, user_id)

Post Controller

Post Routes

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List

from app.core.database import get_db
from app.core.auth import get_current_user
from app.schemas.post import PostCreate, PostUpdate, PostResponse
from app.services.post import PostService
from app.models.user import User

class PostController(BaseController):
    def __init__(self, service: PostService):
        super().__init__(service)

    def _register_routes(self):
        self.router.post("/", response_model=PostResponse)(self.create)
        self.router.get("/", response_model=List[PostResponse])(self.list)
        self.router.get("/{post_id}", response_model=PostResponse)(self.get)
        self.router.put("/{post_id}", response_model=PostResponse)(self.update)
        self.router.delete("/{post_id}")(self.delete)

    async def create(
        self,
        post: PostCreate,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
    ):
        return await self.service.create(db, post, current_user.id)

    async def list(
        self,
        skip: int = 0,
        limit: int = 100,
        db: Session = Depends(get_db)
    ):
        return await self.service.list(db, skip, limit)

    async def get(self, post_id: int, db: Session = Depends(get_db)):
        return await self.service.get(db, post_id)

    async def update(
        self,
        post_id: int,
        post: PostUpdate,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
    ):
        return await self.service.update(db, post_id, post, current_user.id)

    async def delete(
        self,
        post_id: int,
        db: Session = Depends(get_db),
        current_user: User = Depends(get_current_user)
    ):
        return await self.service.delete(db, post_id, current_user.id)

Error Handling

Custom Exceptions

from fastapi import HTTPException, status

class NotFoundException(HTTPException):
    def __init__(self, detail: str = "Resource not found"):
        super().__init__(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=detail
        )

class UnauthorizedException(HTTPException):
    def __init__(self, detail: str = "Not authenticated"):
        super().__init__(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=detail
        )

class ForbiddenException(HTTPException):
    def __init__(self, detail: str = "Not enough permissions"):
        super().__init__(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=detail
        )