ZCore LogoZCore
Quick learn

Step 5 - Schemas & Dynamic Security (Zchema)

Define Pydantic schemas and use Zchema to automatically mask sensitive fields based on user context.

Instead of writing multiple Pydantic models for different user roles (e.g., TaskResponsePublic, TaskResponseAdmin), ZCore provides role-aware field projection through Zchema.

Define Schemas

Open tasks/schemas.py and define your creation, update, and response schemas:

# tasks/schemas.py
import uuid
from zcore import Zchema
from pydantic import ConfigDict

class TaskCreate(Zchema):
    __model__ = "tasks"  # Binds this schema to the Task domain
    
    title: str
    is_completed: bool = False
    assignee_email: str | None = None

class TaskUpdate(Zchema):
    __model__ = "tasks"
    
    title: str | None = None
    is_completed: bool | None = None
    assignee_email: str | None = None

class TaskResponse(Zchema):
    __model__ = "tasks"
    __private__ = {"assignee_email"}  # Automatically hidden for unauthenticated guests
    
    id: uuid.UUID
    title: str
    is_completed: bool
    assignee_email: str | None = None
    
    model_config = ConfigDict(from_attributes=True)

Eliminating Role-Based Schema Duplication

Zchema eliminates the need to maintain duplicate schemas for different permission levels (such as TaskCreatePublic vs TaskCreateAdmin or TaskResponseUser vs TaskResponseAdmin). By dynamically sanitizing inputs (preventing Mass Assignment) and pruning response fields based on ctx.restricted_fields, a single schema definition per operation handles all authorization levels automatically.

How Zchema Works

Context Shielding: By setting __model__ = "tasks", Zchema is now aware of its domain.

During the request lifecycle, if the active user lacks certain permissions, their restricted fields are loaded into ctx.restricted_fields (e.g., "tasks.view.assignee_email").

When TaskResponse serializes the data, Zchema intercepts the process and automatically prunes the assignee_email from the JSON output. No if statements required.

Guest-Level Masking (__private__): In addition to role-based pruning via ctx.restricted_fields, you can declare __private__ = {"assignee_email"} on your Zchema. These fields are automatically pruned for unauthenticated guest requests (ctx.user_id is None) across responses, inputs, and OpenAPI schemas.

We now have secure data transfer objects. Let's build the data access layer.

On this page