Utilities and base classes for FastAPI async projects (Beanie or SQLAlchemy)
Project description
FastAPI BaseKit
FastAPI BaseKit provides asynchronous utilities and base classes to accelerate building APIs with FastAPI using either Beanie (MongoDB) or SQLAlchemy (AsyncSession). It offers a consistent architecture for repositories, services, and controllers with solid typing via Pydantic.
Key Features
- Generic classes for repositories (
BaseRepository), services (BaseService) and controllers (BaseController) ready to extend. - Unified response schemas (
BaseResponseandBasePaginationResponse). - Exception handlers and custom exceptions for common errors.
- Third-party services like JWT token management
- Built to work fully asynchronously, making horizontal scalability easier.
- Support for Beanie ODM and SQLAlchemy (AsyncSession) via optional extras.
- Pluggable query kwargs per action through
get_kwargs_query()in services.
Installation
Core install keeps the package lightweight; choose your ORM with extras.
- Base (no ORM libs):
- pip install fastapi-basekit
- Beanie stack:
- pip install "fastapi-basekit[beanie]"
- SQLAlchemy stack:
- pip install "fastapi-basekit[sqlalchemy]"
- Everything:
- pip install "fastapi-basekit[all]"
Beanie Quickstart
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
from beanie import Document, init_beanie
from motor.motor_asyncio import AsyncIOMotorClient
from fastapi_basekit.aio.beanie.repository.base import BaseRepository
from fastapi_basekit.aio.beanie.service.base import BaseService
from fastapi_basekit.aio.controller.base import BaseController
from fastapi_basekit.exceptions.handler import (
api_exception_handler,
validation_exception_handler,
)
app = FastAPI()
# Beanie model
class Item(Document):
name: str
# Repository
class ItemRepository(BaseRepository):
model = Item
# Service
class ItemService(BaseService):
repository: ItemRepository
search_fields = ["name"]
duplicate_check_fields = ["name"]
# Controller
class ItemController(BaseController):
service: ItemService = Depends()
schema_class = Item
@asynccontextmanager
async def lifespan(app: FastAPI):
client = AsyncIOMotorClient("mongodb://localhost:27017")
await init_beanie(database=client.mydb, document_models=[Item])
yield
app.add_exception_handler(Exception, api_exception_handler)
app.add_exception_handler(ValueError, validation_exception_handler)
controller = ItemController()
app.add_api_route("/items", controller.list, methods=["GET"])
app.add_api_route("/items/{id}", controller.retrieve, methods=["GET"])
app.add_api_route("/items", controller.create, methods=["POST"])
This snippet shows how to inherit the base classes and expose a basic CRUD in FastAPI using Beanie.
Advanced Example
Below is a more complete example that configures middlewares, custom error handlers and a user CRUD separated into repository, service and controller.
from pymongo.errors import DuplicateKeyError
from fastapi import FastAPI, status
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from slowapi import _rate_limit_exceeded_handler
from app.api.v1.routers import api_router
from fastapi_basekit.exceptions import APIException
from app.config.database import lifespan
from app.config.limit import limiter
from app.config.settings import get_settings
from fastapi_basekit.exceptions import (
api_exception_handler,
duplicate_key_exception_handler,
global_exception_handler,
validation_exception_handler,
value_exception_handler,
)
settings = get_settings()
app = FastAPI(
title=settings.PROJECT_NAME,
version=settings.VERSION,
lifespan=lifespan,
redirect_slashes=True,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=[
"*"
], # allow all methods
allow_headers=["*"], # allow all headers
)
app.state.limiter = limiter
app.include_router(api_router, prefix=settings.API_V1_STR)
# Register custom handlers
app.add_exception_handler(
status.HTTP_429_TOO_MANY_REQUESTS, _rate_limit_exceeded_handler
)
app.add_exception_handler(APIException, api_exception_handler)
app.add_exception_handler(RequestValidationError, validation_exception_handler)
app.add_exception_handler(ValueError, value_exception_handler)
app.add_exception_handler(Exception, global_exception_handler)
app.add_exception_handler(DuplicateKeyError, duplicate_key_exception_handler)
# Import and assign the custom_openapi function
from app.config.openapi import custom_openapi # noqa
app.openapi = custom_openapi
from beanie import PydanticObjectId
from fastapi import APIRouter, Body, Depends, Query, status
from fastapi_restful.cbv import cbv
from fastapi_basekit.aio.controller.base import BaseController
from fastapi_basekit.schema.base import BaseResponse
from app.models.user import User
from app.schemas.user.user import (
UserDResponseSchema,
UserPResponseSchema,
UserResponseSchema,
UserURequestSchema,
)
from app.services.dependency.current_user import get_dependency_service
from app.services.system.user.user_service import UserService, get_user_service
router = APIRouter()
@cbv(router)
class UserController(BaseController):
service: UserService = Depends(get_user_service)
user: User = Depends(get_dependency_service)
def get_schema_class(self):
if self.action == "retrieve":
return UserDResponseSchema
else:
return UserResponseSchema
@router.get("/", response_model=UserPResponseSchema)
async def list(
self,
page: int = Query(1, ge=1, description="Page number"),
limit: int = Query(10, ge=1, description="Items per page"),
search: str | None = Query(None, description="Search term"),
):
"""List users with pagination and optional search."""
return await super().list(page=page, count=limit, search=search)
@router.get("/{id}", response_model=BaseResponse[UserDResponseSchema])
async def retrieve(self, id: PydanticObjectId):
return await super().retrieve(id)
@router.patch("/{id}", response_model=BaseResponse[UserResponseSchema])
async def update(
self,
id: PydanticObjectId,
data: UserURequestSchema = Body(...),
):
return await super().update(id, data)
@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete(self, id: PydanticObjectId):
return await super().delete(id)
from fastapi import Request
from fastapi_basekit.aio.beanie.service.base import BaseService
from app.repositories.user.user import UserRepository
class UserService(BaseService):
repository: UserRepository
def __init__(
self, repository: UserRepository = None, request: Request = None
):
super().__init__(repository, request)
self.search_fields = ["name", "email"]
def get_kwargs_query(self):
"""
Return the query arguments for the repository.
Allows customizing queries in child services.
"""
if self.action == "retrieve":
return {
"fetch_links": True,
"nesting_depths_per_field": {"role": 1, "company": 1},
}
return super().get_kwargs_query()
def get_user_service(request: Request) -> UserService:
repo = UserRepository()
service = UserService(request=request, repository=repo)
return service
from fastapi_basekit.aio.beanie.repository.base import BaseRepository
from app.models.user import User
class UserRepository(BaseRepository):
model: User = User
Additional Services
The package includes utilities for common integrations:
- JWTService: create, validate and refresh JWT tokens.
You can import them from fastapi_basekit.servicios and use them like any other FastAPI dependency.
SQLAlchemy (Async) Usage
from typing import Annotated
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi_basekit.aio.sqlalchemy.repository.base import BaseRepository as SARepository
from fastapi_basekit.aio.sqlalchemy.service.base import BaseService as SAService
from fastapi_basekit.aio.sqlalchemy.controller.base import SQLAlchemyBaseController
# Example SQLAlchemy model (simplified)
class UserORM: # replace with your declarative model
id: str
name: str
class UserRepository(SARepository):
model = UserORM
class UserService(SAService):
repository: UserRepository
def get_db() -> AsyncSession: # your session dependency
...
class UserController(SQLAlchemyBaseController):
service: Annotated[UserService, Depends()]
# Provide a Pydantic schema via `schema_class` or override `get_schema_class`
# SQLAlchemyBaseController methods accept `db: AsyncSession` dependency
SQLAlchemy: Customizing joins/order per action
from fastapi_basekit.aio.sqlalchemy.service.base import BaseService as SAService
class UserService(SAService):
def get_kwargs_query(self) -> dict:
# Automatically include joins when listing/retrieving
if self.action in ["retrieve", "list"]:
return {"joins": ["role"], "order_by": None}
return super().get_kwargs_query()
The controller’s list/retrieve will use these kwargs automatically unless explicitly overridden by parameters.
Tests
The project contains tests that validate the main functionality. Install the dependencies defined in pyproject.toml and run:
pytest
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_basekit-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_basekit-0.1.0.tar.gz
- Upload date:
- Size: 19.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5343431219b01dce9fb5d5ab3a73c54b06cfb487c91a459716233615bc791c96
|
|
| MD5 |
823ef6b634ce6dcd9fc8c8bec09345a6
|
|
| BLAKE2b-256 |
4ed2a47467dc4c15e390578c8e370a522b63d1ea859310436b28eb59324b5fb0
|
Provenance
The following attestation bundles were made for fastapi_basekit-0.1.0.tar.gz:
Publisher:
publish.yml on mundobien2025/fastapi-basekit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_basekit-0.1.0.tar.gz -
Subject digest:
5343431219b01dce9fb5d5ab3a73c54b06cfb487c91a459716233615bc791c96 - Sigstore transparency entry: 521641872
- Sigstore integration time:
-
Permalink:
mundobien2025/fastapi-basekit@b7e5b21390f814ab2307d1cc5cce41ada3c82371 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mundobien2025
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b7e5b21390f814ab2307d1cc5cce41ada3c82371 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fastapi_basekit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_basekit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc1924ec07f404c57b69fceb92fee66cbddfaba9eb6f74198fb66572baa93f1a
|
|
| MD5 |
3a6bfa48314a2dfc73fbe9a0c63c10a8
|
|
| BLAKE2b-256 |
f7be0d71257c9a2031439a6ea521cd66a4214c6cb3712565976332fb31e9874a
|
Provenance
The following attestation bundles were made for fastapi_basekit-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on mundobien2025/fastapi-basekit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_basekit-0.1.0-py3-none-any.whl -
Subject digest:
dc1924ec07f404c57b69fceb92fee66cbddfaba9eb6f74198fb66572baa93f1a - Sigstore transparency entry: 521641904
- Sigstore integration time:
-
Permalink:
mundobien2025/fastapi-basekit@b7e5b21390f814ab2307d1cc5cce41ada3c82371 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mundobien2025
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b7e5b21390f814ab2307d1cc5cce41ada3c82371 -
Trigger Event:
push
-
Statement type: