Skip to main content

Ready-made FastAPI abstractions: repository, unit of work, service etc.

Project description

FastAPI Abstractions

Ready-made FastAPI abstractions: repository, unit of work, service etc.

Features

  • Focus on business logic: No need to write boilerplate code.
  • Scalable: You can use the provided abstractions and easily extend them.
  • Portable: Works with any database supported by SQLAlchemy.
  • Intuitive: Great editor support. Completion everywhere. Less time debugging.
  • Easy: Designed to be easy to use and learn. Less time reading docs.
  • Asynchronous: Built-in support for async/await.
  • Use anywhere: Use it with FastAPI, Aiogram, or any other framework (best with FastAPI).

Requirements

FastAPI Abstractions stands on the shoulders of giants:

Installation

pip install fastabc

Concepts

1. Models

from datetime import datetime

from sqlalchemy import Identity
from sqlalchemy.orm import Mapped, mapped_column

from fastabc import DeclarativeBase, AlchemyEntity
from fastabc.alchemy import SoftDeletable, HasID, HasTimestamp


# Classic way
class User(DeclarativeBase):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(Identity(), primary_key=True)
    email: Mapped[str] = mapped_column(unique=True, index=True)
    password: Mapped[str]
    created_at: Mapped[datetime] = mapped_column(default=datetime.now)
    updated_at: Mapped[datetime] = mapped_column(
        default=datetime.now, onupdate=datetime.now
    )


# Using AlchemyEntity
class UserAlchemyEntity(AlchemyEntity):
    __tablename__ = "users"

    email: Mapped[str] = mapped_column(unique=True, index=True)
    password: Mapped[str]

    # These columns will be added automatically
    # id: Mapped[int] = mapped_column(Identity(), primary_key=True)
    # created_at: Mapped[datetime] = mapped_column(default=datetime.now)
    # updated_at: Mapped[datetime] = mapped_column(
    #     default=datetime.now, onupdate=datetime.now
    # )


# Using mixins
class UserMixins(HasID, HasTimestamp, SoftDeletable):
    __tablename__ = "users"

    email: Mapped[str] = mapped_column(unique=True, index=True)
    password: Mapped[str]
    # These columns will be added automatically
    # id: Mapped[int]
    # created_at: Mapped[datetime] = mapped_column(default=datetime.now)
    # updated_at: Mapped[datetime] = mapped_column(
    #     default=datetime.now, onupdate=datetime.now
    # )
    # deleted_at: Mapped[datetime | None] = None

2. Repositories

from fastabc import AlchemyRepository
from .models import User


class UserRepository(AlchemyRepository[User]):
    model_type = User

3. Unit of Work

from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

from fastabc import AlchemyUOW
from .repositories import UserRepository


class UOW(AlchemyUOW):
    users: UserRepository

    async def on_open(self) -> None:
        self.users = UserRepository(self.session)


async_engine = create_async_engine("sqlite+aiosqlite:///memory")
async_session = async_sessionmaker(async_engine)

uow = UOW(async_session)

4. Services

from fastabc import AlchemyService
from .models import User
from .uow import UOW


class UserService(AlchemyService):
    uow: UOW

    async def create(self, email: str, password: str) -> User:
        user = User(email=email, password=password)
        self.uow.users.add(user)
        await self.uow.commit()

        return user

    async def get(self, user_id: int) -> User | None:
        return await self.uow.users.get(user_id)

    async def get_by_email(self, email: str) -> User | None:
        return await self.uow.users.get_by_where(where=[User.email == email])

    async def create_many(self, users: list[User]) -> list[User]:
        await self.uow.users.insert(*users)
        await self.uow.commit()

        return users

    async def get_by_domain(self, domain: str) -> list[User]:
        return await self.uow.users.get_many(where=[User.email.like(f"%@{domain}")])

    # And more...

5. Use Cases

from faker import Faker

from .models import User
from .service import UserService
from .uow import uow

fake = Faker()


def get_users(domains: list[str], number: int = 10) -> list[User]:
    users = [User(email=fake.email(domain=domain), password=fake.password()) for _ in range(number) for domain in
             domains]
    return users


async def main():
    async with uow:
        service = UserService(uow)

        user = await service.create("user@example.com", "qwerty12345")
        print(user)

        user = await service.get(user.id)
        print(user)

        user = await service.get_by_email("user@example.com")
        print(user)

        users = get_users(["gmail.com", "yahoo.com"])
        await service.create_many(*users)

        users = await service.get_by_domain("gmail.com")
        print(users)

Made with love ❤️

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastabc-0.1.7.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

fastabc-0.1.7-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file fastabc-0.1.7.tar.gz.

File metadata

  • Download URL: fastabc-0.1.7.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.12.3 Windows/11

File hashes

Hashes for fastabc-0.1.7.tar.gz
Algorithm Hash digest
SHA256 e29e1f10ec83703801e6431eda71a1f4ec47feb3c2f466173d9e05657e25ac71
MD5 4206ce61065c1329bcf0243609444c45
BLAKE2b-256 9e4df3957a5c163bf4b8ead0daed57cf354a822f4cc487b2cad12272dc0314f9

See more details on using hashes here.

File details

Details for the file fastabc-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: fastabc-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.12.3 Windows/11

File hashes

Hashes for fastabc-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 12fdadb92da6e4b36ffb81a889fc9ae70fa5ffc14ed6bf7c731b2fa7d378a727
MD5 f3921a6dda2dd200faeafe0b8797d5cd
BLAKE2b-256 ea7dca5cd3c0cc32c12ca626dd68e3f7f9526782250e6fcfce50868f1e00e163

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page