ZCore LogoZCore

What is ZCore?

A modular architectural framework designed for FastAPI by Baseryn. Use an isolated component or adopt the full stack — your code stays standard FastAPI.

Core Definition

FastAPI ZCore Framework is a high-performance modular architectural framework built on top of FastAPI, created by Ali Alf Ostovar and maintained by Baseryn.

It provides a cohesive set of enterprise-grade design patterns—such as constructor dependency injection with auto-wiring, repository pattern abstractions with bulk mutation optimizations, complete soft-delete restoration lifecycles, dynamic schema projections (Zchema), automated 8-endpoint CRUD/Lookup scaffolding, transactional Unit of Work, unified exception normalization with debug-gated diagnostics, and isolated background tasks—designed to eliminate repetitive boilerplate in growing, high-throughput FastAPI applications.

Every architectural layer in ZCore is strictly opt-in. You can adopt a single pattern in an existing codebase, combine multiple layers, or ignore them entirely. Your application remains a standard FastAPI project at its core.


What ZCore is NOT

Misconceptions often arise when comparing modular frameworks to monolithic, opinionated tools. Here is how ZCore differs:

ZCore is NOTWhy this misconception occursThe Architectural Reality
A rigid framework (like Django)It features CLI scaffolding and architectural base classes.The zc CLI generates clean, standard files that you can freely modify or delete. Base classes provide flexible working defaults, not enforced monolithic structures.
An enterprise monolithIt includes Unit of Work and plugin management.UnitOfWork is a lightweight context manager; Plugin is an optional startup registry with DAG topological sorting. Both function seamlessly even in a small, two-file project.
A replacement for FastAPIIt exposes its own classes and is imported via zcore.ZCore extends FastAPI natively. You continue writing standard @router endpoints, using native Pydantic models, and leveraging Depends(). ZCore simply offers higher-level architectural abstractions.
Opinionated or intrusiveIt provides pre-built Base classes.Every method across ZCore base components is fully overridable. "Base" implies a sensible default implementation, not a closed black box.
All-or-nothingIt carries the umbrella name of a framework.You can import and use Inject[T], background_task, register_exception_handlers, or BaseRepository independently in a project that utilizes zero other ZCore modules.

Architectural Rule: If a specific ZCore component does not directly solve a structural pain point in your route, model, or service, do not use it. ZCore never imposes self-dependency.


How ZCore Relates to FastAPI

ZCore does not wrap or abstract away FastAPI; it runs alongside it.

  • Standard Routing: You retain full access to FastAPI's APIRouter, native background tasks, and exception handlers.
  • Native Pydantic V2: ZCore models (Zchema) inherit directly from Pydantic BaseModel, ensuring 100% compatibility with native data validation pipelines.
  • Dependency Injection Integration: Inject[T] compiles internally down to standard FastAPI Annotated[T, Depends()] structures, keeping OpenAPI introspection, Swagger UI documentation, and dependency overrides fully intact.
  • Unified Error Normalization: Integrates with Starlette and FastAPI exception lifecycles to automatically wrap domain errors, 422 validation issues, and uncaught 500 runtime exceptions into a single structured envelope (ResponseWrapper), sanitizing Pydantic error traces and gating server internals in production.
  • Async Native: Built specifically for async Python 3.11+, SQLAlchemy 2.0 Async, and ASGI middleware lifecycles.

Core Design Principles

1. Optional by Default

There is no global initialization hook or mandatory app factory that hijacks your project structure. You import and instantiate precisely what you require:

# Import and use only the DI container helper — nothing else
from zcore import Inject

class NotificationService:
    def __init__(self, client: Inject[EmailClient]):
        self.client = client

2. Overridable by Design

Base classes are structured to be extended or replaced. If a default implementation does not match your business rules, override it cleanly:

from typing import Any
from zcore import BaseService
from pydantic import BaseModel

class TaskService(BaseService[Task]):
    # Override a specific lifecycle hook (Hooks live in the Service layer)
    async def pre_create(self, schema: TaskCreate) -> dict[str, Any] | None:
        return {"slug": slugify(schema.title)}

    # Or override the entire core method when absolute control is needed
    async def on_create(self, schema: BaseModel, **extra_data: Any) -> Task:
        task = await self.repository.create(schema, **extra_data)
        await external_cache.set(f"task:{task.id}", task)
        return task

3. Composable, Not Coupled

You can mix and match ZCore components with native FastAPI patterns freely:

from zcore import BaseRepository, Inject

class TaskRepo(BaseRepository[Task]):
    pass

@router.get("/tasks")
async def list_tasks(repo: Inject[TaskRepo]):
    # Includes dynamic search, soft-delete, and restoration out-of-the-box
    return await repo.get_list()

No service layer, no base router—just clean repository abstraction.


Boundaries: What ZCore Does NOT Do

Clarity regarding framework boundaries helps determine when ZCore is an appropriate fit:

ZCore does NOTUnderlying Implementation / Alternative
Replace SQLAlchemyZCore builds directly on top of SQLAlchemy 2.0 async engines and sessions.
Replace PydanticZCore extends Pydantic V2 via Zchema for field-level security projection.
Enforce strict project layoutsThe zc CLI provides an interactive, modular scaffolding wizard; you can adapt or delete it.
Manage database migrationsUse Alembic directly for full control over migration histories.
Provide built-in user authentication UIIt offers BaseAuth utilities and Argon2id hashing, but authentication state and models are yours to define.

When to Adopt ZCore (And When to Skip It)

ZCore helps when...

  • You are writing repetitive CRUD and field-projected lookup endpoints across multiple models.
  • You need full soft-delete lifecycles, batch restorations (restore_multi), and hard-delete bypasses (?force=true).
  • You need dynamic, role-based field visibility on schemas without maintaining dozens of duplicate Pydantic models.
  • You require atomic multi-table writes with deferred event publishing via Unit of Work.
  • You prefer clean constructor injection with auto-wiring over verbose, nested Depends() parameters.
  • You need to run asynchronous background routines with guaranteed database session and context isolation.
  • You want a unified, production-safe error envelope across all domain, validation, and unhandled 500 exceptions.

ZCore is unnecessary when...

  • Your application consists of 1–2 simple endpoints with minimal business logic.
  • You have no requirements for field-level security masking or complex audit trails.
  • You prefer writing explicit, manual Depends() chains and inline SQL statements.

Pragmatic Rule: If your FastAPI application is scaling cleanly and meeting your architectural needs without friction, you do not need ZCore. Adopt ZCore only when addressing specific structural scaling bottlenecks.


The Adoption Spectrum

You control the pace of adoption. Moving rightward along the spectrum is entirely optional and driven solely by project growth:

  1. Plain FastAPI (Zero ZCore dependencies)
  2. Targeted Utilities (Adopting Inject[T], background_task, register_exception_handlers, or UnitOfWork)
  3. Data Access Layer (BaseRepository with soft-delete/restoration, and BaseService)
  4. Security & Projection (Zchema for role-based field filtering and input protection)
  5. Full Orchestration (BaseRouter with 8 standard endpoints including /lookup, and modular Plugin architectures)

Explore the Components

On this page